AI code block
ai-ui specs/ai-ui/code-block.kmd
AI-generated code rendering with language detection, syntax highlight, copy button, optional run button, diff view, and defer-until-fence contract during streaming. Hosted by chat-message-bubble (#105) and artifact panel (#110). Shares syntax token vocabulary with themes/color-schemes.kmd.
When this spec applies
Primary triggers
- Display fenced code block from AI response
All triggers
- Render AI-generated code in any Koder surface
- Implement Kortex/Kode code-aware response
- Add diff view when AI edits existing file
Specification body
Spec — AI code block
Sintaxe tokens consumidos do
themes/color-schemes.kmd"Vocabulário syntax". Defer-until-fence durante streaming viastreaming-text.kmdR4. Hospedado porchat-message-bubble.kmdR5 (content typecode) eartifact-panel.kmd(#110).
Princípios
- Defer until closed — code blocks NOT highlighted during stream until closing fence (cross-link #106 R4).
- Copy always full — copy button gives unsanitized source; never truncated.
- Run is opt-in per host — Run button only when host has executor (Kortex liga; Talk não).
- Diff when modifying — AI editing existing file → side-by-side OR unified diff.
- Security boundary — Run never
eval()s; uses sandboxed executor (Koda runtime, WebAssembly, or external worker).
R1 — Anatomia
┌──────────────────────────────────────────┐
│ python · 12 lines [⎘ ▶ ⇕] │ ← header
├──────────────────────────────────────────┤
│ 1 def fibonacci(n): │
│ 2 if n <= 1: │
│ 3 return n │
│ 4 return fibonacci(n-1) + fibonacci(n-2)
│ 5 │
│ 6 print(fibonacci(10)) │
└──────────────────────────────────────────┘
Slots:
| Slot | Conteúdo |
|---|---|
| Language label | Detected language (per R2) |
| Line count | "{N} lines" |
| Actions | Copy ⎘ · (Run ▶ if executor present) · Diff toggle ⇕ (if applicable) |
| Body | Syntax-highlighted code with optional line numbers |
Mono font: JetBrains Mono per themes/typography.kmd R1.
R2 — Language detection
Order of resolution:
- Markdown fence info string: ```python →
python. - Filename hint (if AI provides via custom block attribute):
.dart→dart. - Heuristic: first-line shebang (
#!/usr/bin/env python). - Token-based detection (per surface library:
flutter_highlight,prismjs, etc.). - Fallback:
plaintext.
Detected language displayed in header.
R3 — Syntax highlighting
Tokens consumed from themes/color-schemes.kmd:
| Token | Example |
|---|---|
syntax_keyword | def, class, if, return |
syntax_string | "hello", 'world' |
syntax_number | 42, 3.14 |
syntax_comment | # this is a comment |
syntax_function | fibonacci, print |
syntax_type | int, str, List |
syntax_constant | True, None, null |
syntax_operator | +, ==, => |
syntax_punctuation | (, ), ,, ; |
Per-preset color mapping via themes/color-schemes.kmd (não duplicar
aqui).
Highlighting engine: per surface (Flutter flutter_highlight-compatible;
Web prismjs-compatible; CLI uses chroma or equivalent). Surfaces
MUST honor token vocabulary acima; engine choice é impl detail.
R4 — Copy button
Behavior:
- Tap copy → write full unmodified source to clipboard.
- Visual feedback: toast "Copied to clipboard" (i18n) per 1.5s.
- Anti-pattern: Copy NEVER truncated. Even when display truncates per R7, clipboard has full.
R5 — Run button (opt-in per host)
Visible only when host declares executor capability:
KoderAICodeBlock(
code: ...,
language: "python",
executor: KoderKodaSandbox(), // or null = no Run button
)
Behavior:
- Tap Run → execute via passed executor.
- Spinner during execution.
- Output appended below code block in collapsible "Output" section.
- Errors displayed inline with error styling.
Security: executor MUST be sandbox-isolated. Options:
| Executor | Sandbox |
|---|---|
| Koda runtime | Native Koda VM with capability whitelist |
| WebAssembly | wasmtime/wasmer with WASI-restricted |
| External worker | Sub-process com syscall filter |
| Remote (cloud) | services/ai/sandbox LXC |
NEVER use raw eval() / Function() / exec(). NEVER trust AI-generated
code to be safe (cross-link policies/security.kmd).
R6 — Diff view
When AI edits existing file, response includes diff metadata:
{
"content": [{
"type": "code",
"code": "def fibonacci(n):\n ...",
"language": "python",
"diff": {
"mode": "edit",
"original_path": "lib/math.py",
"original_content": "def fib(n):\n ...",
"edits": [...]
}
}]
}
Diff toggle button switches body between:
- Code view: just new code (default for new files).
- Side-by-side diff: original | new (default for edits).
- Unified diff: standard
+/-markers.
Diff lib per surface: flutter_diff_view, diff2html, etc.
R7 — Truncation (display only)
Long code blocks (>50 lines): collapse with "Show more" after 50 lines. Copy + Run always operate on FULL source (R4).
R8 — Surface bindings
| Surface | API |
|---|---|
| Flutter | KoderAICodeBlock({required code, required language, executor?, diff?}) em koder_kit/lib/src/ai/ai_code_block.dart |
| Web | <koder-ai-code-block language="..." code="..."> em koder_web_kit |
| Compose Android | KoderAICodeBlock (futuro) |
| SwiftUI iOS | idem (futuro) |
| CLI / TUI | Plain text with chroma highlighting; copy via OSC52; no run button |
R9 — Acessibilidade
- Code container:
role="region" aria-label="Code block, {language}, {N} lines". - Line numbers:
aria-hidden="true"(não anunciar). - Syntax color: MUST atender AAA contrast (cross-link
themes/color-roles.kmdR4). - Copy button:
aria-label="Copy code to clipboard". - Run button:
aria-label="Run code". - Keyboard: Tab through code → block focuses → Tab again → actions.
- Screen reader: announces language + line count; code can be read line by line.
R10 — i18n
| Key | en-US | pt-BR |
|---|---|---|
ai.code.action.copy | "Copy code" | "Copiar código" |
ai.code.action.copy.success | "Copied" | "Copiado" |
ai.code.action.run | "Run code" | "Executar código" |
ai.code.action.diff_toggle | "Toggle diff view" | "Alternar visualização de diff" |
ai.code.label.lines | "{n} lines" | "{n} linhas" |
ai.code.label.language | "Language: {lang}" | "Linguagem: {lang}" |
ai.code.output.header | "Output" | "Saída" |
ai.code.run.error | "Execution failed" | "Falha na execução" |
ai.code.show_more | "Show more" | "Mostrar mais" |
R11 — Per-preset variation
| Preset | Code block style |
|---|---|
material3 / material_expressive | Default; rounded; shadow |
material2 | Default; smaller radius |
terminal_classic | Plain text in bg-inset; no border; no shadow |
brutalist | Sharp corners; 2px solid border |
cyberpunk_neon | Glow border in accent; gradient backdrop |
glassmorphism | Backdrop blur; 20% surface tint |
minimalist_mono | Single bottom-border; no background fill |
T-suite
- T1 Render code: code + language → syntax highlighted body + header showing language + line count.
- T2 Language detection: code without fence info but with
#!/python→ detected as python. - T3 Copy full: tap copy → clipboard equals full source even when display truncated > 50 lines.
- T4 Copy toast: tap copy → "Copied" toast appears.
- T5 Run available: pass executor → Run button visible; tap → executor invoked.
- T6 Run unavailable: no executor → no Run button.
- T7 Diff view edit: receive diff metadata with mode="edit" → diff toggle visible; tap → side-by-side rendered.
- T8 Defer during stream (cross-link #106 T6): code block fenced opens mid-stream → placeholder "(writing code…)"; on close → syntax highlight done ONCE.
- T9 Truncation: 100-line code → 50 lines visible + "Show more"; copy still has 100 lines.
- T10 Security: Run with malicious code (e.g.,
os.system('rm -rf /')) → sandbox prevents file system access; capability error surfaces. - T11 A11y: screen reader announces "Code block, python, 12 lines"; copy button has aria-label.
- N1 Run without executor: spec validation prevents calling onRun when executor=null.
- N2 Syntax engine fallback: unsupported language → renders as plaintext (no crash).
Cross-link
- Companion:
chat-message-bubble.kmd(host),streaming-text.kmdR4 (defer),artifact-panel.kmd(alternate host for large code),agent-step-trace.kmd(step body may include code) - Syntax tokens:
themes/color-schemes.kmd - Typography:
themes/typography.kmdR8 (code typography) - Color contrast:
themes/color-roles.kmdR4 AAA - Security:
policies/security.kmd(executor sandbox) - Executor:
services/ai/sandbox/,engines/lang/koda/runtime/(Koda VM) - Refs: Claude Artifacts, ChatGPT code blocks, GitHub Copilot diff
References
meta/docs/stack/specs/ai-ui/chat-message-bubble.kmdmeta/docs/stack/specs/ai-ui/streaming-text.kmdmeta/docs/stack/specs/ai-ui/artifact-panel.kmdmeta/docs/stack/specs/themes/color-schemes.kmdmeta/docs/stack/policies/security.kmd