feat(web): shiki syntax highlighting for code surfaces

One highlighter for the client: a synchronous fine-grained shiki core
(JS regex engine, no WASM) in ui-primitives with an explicit grammar
allowlist (typescript, shellscript, json — aliases resolve, unknown
languages take a geometry-identical plain arm). The shared CodeBlock
component owns both arms; markdown fences, the run_code expanded
program body (typescript), and the details panel Input (json) all
route through it. Token colors live in a new ui-theme shiki.css sheet
as --shiki-* custom properties (light/dark blocks), wired through the
shell's base.css chain — tokens-only styling holds; shiki's generated
span tree is the sanctioned innerHTML path (static output, no user
HTML). jsdom specs pin token spans, aliases, both fallbacks, and the
fence route; the built-bundle snapshot asserts the highlighted program
under the code row.
This commit is contained in:
Tianyi Cui
2026-07-26 09:52:37 +08:00
parent 4987261d55
commit bb3dc50a4b
17 changed files with 399 additions and 19 deletions
@@ -87,14 +87,9 @@ button.leading {
color: var(--dsw-alias-label-tertiary);
}
/* The code variant's expanded body is the run_code program: monospace on the
markdown code-block fill so the program reads as code, not prose. */
.root[data-variant='code'] .body {
font-family: var(--ds-font-family-code);
font-size: 13px;
line-height: 20px;
padding: 6px 8px;
margin-left: 22px;
border-radius: 6px;
background: var(--dsw-alias-markdown-code-block);
/* The code variant's expanded body is the run_code program, rendered through
the shared CodeBlock (shiki-highlighted TypeScript); only indentation is
this row's concern. */
.codeBody {
margin: 4px 0 4px 22px;
}
@@ -6,7 +6,7 @@
import { useState, type KeyboardEvent, type MouseEvent, type ReactNode } from 'react'
import clsx from 'clsx'
import { StateDot } from '@deepseek-ai/dsh-client-ui-primitives'
import { CodeBlock, StateDot } from '@deepseek-ai/dsh-client-ui-primitives'
import { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'
import type { ToolRowState, ToolRowVariant } from '../contract/tool-call-model.ts'
import css from './ToolRow.module.css'
@@ -96,7 +96,9 @@ export function ToolRow({
</>
)}
</div>
{open && <div className={css.body}>{body}</div>}
{open && (variant === 'code'
? <CodeBlock code={body} lang="typescript" className={css.codeBody} />
: <div className={css.body}>{body}</div>)}
</div>
)
}
@@ -5,6 +5,7 @@
// share the store seat exists for) and derives the call material from the
// session snapshot — no data of its own.
import { CodeBlock } from '@deepseek-ai/dsh-client-ui-primitives'
import { shallowEqual } from '@deepseek-ai/dsh-client-runtime/client'
import type { ConversationSnapshot, ToolResultNode } from '@deepseek-ai/dsh-client-runtime/client'
import type { DetailsSlotProps } from '../contract/slots.ts'
@@ -89,7 +90,7 @@ export function DetailsPanel({ useSession, useStore, closeDetails }: DetailsPane
{material.argsRaw !== null && (
<section className={css.section}>
<div className={css.sectionLabel}>Input</div>
<pre className={css.code}>{pretty(material.argsRaw)}</pre>
<CodeBlock code={pretty(material.argsRaw)} lang="json" />
</section>
)}
<section className={css.section}>