From 40cb17d0eb8dafa01097f1c0da0cd97163339a88 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Thu, 23 Oct 2025 21:38:16 +0100 Subject: [PATCH] Fix syntax highlighting by upgrading to Shiki v3 with all languages - Upgrade shiki from ^1.0.0 to ^3.13.0 - Use shiki/bundle/full with all bundled languages (200+) - Change getHighlighter to createHighlighter (v3 API) - Fix CodeBlockInline to track reactive dependencies (theme, code, language) - Add markdown code block detection in tool call outputs - Render tool outputs with Markdown component when they contain code blocks - Support syntax highlighting for bash, webfetch, and default tool outputs --- package.json | 2 +- src/components/code-block-inline.tsx | 5 +++- src/components/tool-call.tsx | 36 ++++++++++++++++++++++++++++ src/lib/markdown.ts | 6 ++--- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f942e07b..4db9e142 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "electron": "38.4.0", "lucide-solid": "^0.300.0", "marked": "^12.0.0", - "shiki": "^1.0.0", + "shiki": "^3.13.0", "solid-js": "^1.8.0" }, "devDependencies": { diff --git a/src/components/code-block-inline.tsx b/src/components/code-block-inline.tsx index ada17766..9322d5b5 100644 --- a/src/components/code-block-inline.tsx +++ b/src/components/code-block-inline.tsx @@ -1,5 +1,5 @@ import { createSignal, onMount, Show, createEffect } from "solid-js" -import type { Highlighter } from "shiki" +import type { Highlighter } from "shiki/bundle/full" import { useTheme } from "../lib/theme" import { getSharedHighlighter, escapeHtml } from "../lib/markdown" @@ -23,6 +23,9 @@ export function CodeBlockInline(props: CodeBlockInlineProps) { createEffect(() => { if (ready()) { + isDark() + props.code + props.language updateHighlight() } }) diff --git a/src/components/tool-call.tsx b/src/components/tool-call.tsx index fa250e80..cd6e2d29 100644 --- a/src/components/tool-call.tsx +++ b/src/components/tool-call.tsx @@ -1,6 +1,8 @@ import { createSignal, Show, For, createEffect } from "solid-js" import { isToolCallExpanded, toggleToolCallExpanded } from "../stores/tool-call-state" import { CodeBlockInline } from "./code-block-inline" +import { Markdown } from "./markdown" +import { useTheme } from "../lib/theme" interface ToolCallProps { toolCall: any @@ -96,7 +98,12 @@ function getLanguageFromPath(path: string): string | undefined { return ext ? langMap[ext] : undefined } +function hasMarkdownCodeBlocks(text: string): boolean { + return /```[\s\S]*?```/.test(text) +} + export default function ToolCall(props: ToolCallProps) { + const { isDark } = useTheme() const toolCallId = () => props.toolCallId || props.toolCall?.id || "" const expanded = () => isToolCallExpanded(toolCallId()) @@ -345,6 +352,17 @@ export default function ToolCall(props: ToolCallProps) { if (input.command) { const fullOutput = `$ ${input.command}${output ? "\n" + output : ""}` + + if (output && hasMarkdownCodeBlocks(output)) { + return ( +
+
+ +
+
+ ) + } + return (
@@ -362,6 +380,15 @@ export default function ToolCall(props: ToolCallProps) { if (output) { const lines = output.split("\n") const truncated = lines.slice(0, 10).join("\n") + + if (hasMarkdownCodeBlocks(truncated)) { + return ( +
+ +
+ ) + } + return } @@ -448,6 +475,15 @@ export default function ToolCall(props: ToolCallProps) { if (output) { const lines = output.split("\n") const truncated = lines.slice(0, 10).join("\n") + + if (hasMarkdownCodeBlocks(truncated)) { + return ( +
+ +
+ ) + } + return } diff --git a/src/lib/markdown.ts b/src/lib/markdown.ts index f5acb486..2899720c 100644 --- a/src/lib/markdown.ts +++ b/src/lib/markdown.ts @@ -1,5 +1,5 @@ import { marked } from "marked" -import { getHighlighter, type Highlighter } from "shiki" +import { createHighlighter, type Highlighter, bundledLanguages } from "shiki/bundle/full" let highlighter: Highlighter | null = null let highlighterPromise: Promise | null = null @@ -15,9 +15,9 @@ async function getOrCreateHighlighter() { return highlighterPromise } - highlighterPromise = getHighlighter({ + highlighterPromise = createHighlighter({ themes: ["github-light", "github-dark"], - langs: [], + langs: Object.keys(bundledLanguages), }) highlighter = await highlighterPromise