Skip to content

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

All triggers

Specification body

Spec — AI code block

Sintaxe tokens consumidos do themes/color-schemes.kmd "Vocabulário syntax". Defer-until-fence durante streaming via streaming-text.kmd R4. Hospedado por chat-message-bubble.kmd R5 (content type code) e artifact-panel.kmd (#110).

Princípios

  1. Defer until closed — code blocks NOT highlighted during stream until closing fence (cross-link #106 R4).
  2. Copy always full — copy button gives unsanitized source; never truncated.
  3. Run is opt-in per host — Run button only when host has executor (Kortex liga; Talk não).
  4. Diff when modifying — AI editing existing file → side-by-side OR unified diff.
  5. 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:

SlotConteúdo
Language labelDetected language (per R2)
Line count"{N} lines"
ActionsCopy ⎘ · (Run ▶ if executor present) · Diff toggle ⇕ (if applicable)
BodySyntax-highlighted code with optional line numbers

Mono font: JetBrains Mono per themes/typography.kmd R1.

R2 — Language detection

Order of resolution:

  1. Markdown fence info string: ```python → python.
  2. Filename hint (if AI provides via custom block attribute): .dartdart.
  3. Heuristic: first-line shebang (#!/usr/bin/env python).
  4. Token-based detection (per surface library: flutter_highlight, prismjs, etc.).
  5. Fallback: plaintext.

Detected language displayed in header.

R3 — Syntax highlighting

Tokens consumed from themes/color-schemes.kmd:

TokenExample
syntax_keyworddef, class, if, return
syntax_string"hello", 'world'
syntax_number42, 3.14
syntax_comment# this is a comment
syntax_functionfibonacci, print
syntax_typeint, str, List
syntax_constantTrue, 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:

ExecutorSandbox
Koda runtimeNative Koda VM with capability whitelist
WebAssemblywasmtime/wasmer with WASI-restricted
External workerSub-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

SurfaceAPI
FlutterKoderAICodeBlock({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 AndroidKoderAICodeBlock (futuro)
SwiftUI iOSidem (futuro)
CLI / TUIPlain 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.kmd R4).
  • 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

Keyen-USpt-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

PresetCode block style
material3 / material_expressiveDefault; rounded; shadow
material2Default; smaller radius
terminal_classicPlain text in bg-inset; no border; no shadow
brutalistSharp corners; 2px solid border
cyberpunk_neonGlow border in accent; gradient backdrop
glassmorphismBackdrop blur; 20% surface tint
minimalist_monoSingle 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).

References