AI code block

mandatory

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.

Spec — AI code block

Sintaxe tokens consumidos do themes/color-schemes.kmd "Vocabulário syntax". Deferuntilfence 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. *efer until closed*— code blocks NOT highlighted during stream until closing fence (cross-link #106 R4).
  2. *opy always full*— copy button gives unsanitized source; never truncated.
  3. *un is opt-in per host*— Run button only when host has executor (Kortex liga; Talk não).
  4. *iff when modifying*— AI editing existing file → sidebyside OR unified diff.
  5. *ecurity 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:

  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:

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 (, ), ,, ;

Perpreset color mapping via `themes/colorschemes.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 *ull 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.

*ecurity* 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:

  • *ode view* just new code (default for new files).
  • *idebyside diff* original | new (default for edits).
  • *nified 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 (crosslink `themes/colorroles.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

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

  • *1*Render code: code + language → syntax highlighted body + header showing language + line count.
  • *2*Language detection: code without fence info but with #!/python → detected as python.
  • *3*Copy full: tap copy → clipboard equals full source even when display truncated > 50 lines.
  • *4*Copy toast: tap copy → "Copied" toast appears.
  • *5*Run available: pass executor → Run button visible; tap → executor invoked.
  • *6*Run unavailable: no executor → no Run button.
  • *7*Diff view edit: receive diff metadata with mode="edit" → diff toggle visible; tap → sidebyside rendered.
  • *8*Defer during stream (crosslink #106 T6): code block fenced opens midstream → placeholder "(writing code…)"; on close → syntax highlight done ONCE.
  • *9*Truncation: 100-line code → 50 lines visible + "Show more"; copy still has 100 lines.
  • *10*Security: Run with malicious code (e.g., os.system('rm -rf /')) → sandbox prevents file system access; capability error surfaces.
  • *11*A11y: screen reader announces "Code block, python, 12 lines"; copy button has aria-label.
  • *1*Run without executor: spec validation prevents calling onRun when executor=null.
  • *2*Syntax engine fallback: unsupported language → renders as plaintext (no crash).

Source: ../home/koder/dev/koder/meta/docs/stack/specs/ai-ui/code-block.kmd