diff --git a/src/components/ChatMessage.tsx b/src/components/ChatMessage.tsx index b0c0d20..0a19b0a 100644 --- a/src/components/ChatMessage.tsx +++ b/src/components/ChatMessage.tsx @@ -5,6 +5,7 @@ import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import remarkBreaks from 'remark-breaks'; import rehypeHighlight from 'rehype-highlight'; +import { rehypeHighlightOptions } from '../lib/highlight'; import type { ChatMessage as ChatMessageType, MessageBlock } from '../types'; import { ThinkingBlock } from './ThinkingBlock'; import { ThinkingIndicator } from './ThinkingIndicator'; @@ -169,7 +170,7 @@ const markdownComponents = { pre: CodeBlock, img: MarkdownImage, a: MarkdownLink function renderTextBlocks(blocks: MessageBlock[]) { return getTextBlocks(blocks).map((block, i) => (
- + {autoFormatText((block as Extract).text)}
@@ -470,7 +471,7 @@ export function ChatMessageComponent({ message: rawMessage, onRetry, agentAvatar {/* User-visible text */} {message.blocks.length > 0 ? renderTextBlocks(message.blocks) : (
- + {autoFormatText(message.content)}
diff --git a/src/components/ToolCall.tsx b/src/components/ToolCall.tsx index eee7a23..7367187 100644 --- a/src/components/ToolCall.tsx +++ b/src/components/ToolCall.tsx @@ -1,6 +1,6 @@ import { useState, useCallback, useMemo, useEffect, useRef } from 'react'; import { ChevronRight, ChevronDown, Check, Copy, WrapText, AlignLeft } from 'lucide-react'; -import hljs from 'highlight.js/lib/common'; +import hljs from '../lib/highlight'; import { useT } from '../hooks/useLocale'; import { ImageBlock } from './ImageBlock'; import { useToolCollapse } from '../hooks/useToolCollapse'; diff --git a/src/lib/highlight.ts b/src/lib/highlight.ts new file mode 100644 index 0000000..5392202 --- /dev/null +++ b/src/lib/highlight.ts @@ -0,0 +1,80 @@ +/** + * Custom highlight.js bundle with only the languages relevant for + * a coding-assistant chat UI. This replaces `highlight.js/lib/common` + * (36 languages) with a focused subset (~16), cutting bundle size significantly. + */ +import hljs from 'highlight.js/lib/core'; +import type { LanguageFn } from 'highlight.js'; + +// Languages commonly seen in AI assistant conversations +import bash from 'highlight.js/lib/languages/bash'; +import css from 'highlight.js/lib/languages/css'; +import diff from 'highlight.js/lib/languages/diff'; +import dockerfile from 'highlight.js/lib/languages/dockerfile'; +import go from 'highlight.js/lib/languages/go'; +import ini from 'highlight.js/lib/languages/ini'; +import javascript from 'highlight.js/lib/languages/javascript'; +import json from 'highlight.js/lib/languages/json'; +import markdown from 'highlight.js/lib/languages/markdown'; +import python from 'highlight.js/lib/languages/python'; +import rust from 'highlight.js/lib/languages/rust'; +import shell from 'highlight.js/lib/languages/shell'; +import sql from 'highlight.js/lib/languages/sql'; +import typescript from 'highlight.js/lib/languages/typescript'; +import xml from 'highlight.js/lib/languages/xml'; +import yaml from 'highlight.js/lib/languages/yaml'; + +hljs.registerLanguage('bash', bash); +hljs.registerLanguage('css', css); +hljs.registerLanguage('diff', diff); +hljs.registerLanguage('dockerfile', dockerfile); +hljs.registerLanguage('go', go); +hljs.registerLanguage('ini', ini); +hljs.registerLanguage('javascript', javascript); +hljs.registerLanguage('json', json); +hljs.registerLanguage('markdown', markdown); +hljs.registerLanguage('python', python); +hljs.registerLanguage('rust', rust); +hljs.registerLanguage('shell', shell); +hljs.registerLanguage('sql', sql); +hljs.registerLanguage('typescript', typescript); +hljs.registerLanguage('xml', xml); +hljs.registerLanguage('yaml', yaml); + +// Aliases for hljs direct usage (ToolCall.tsx) +hljs.registerAliases(['sh', 'zsh'], { languageName: 'bash' }); +hljs.registerAliases(['js', 'jsx'], { languageName: 'javascript' }); +hljs.registerAliases(['ts', 'tsx'], { languageName: 'typescript' }); +hljs.registerAliases(['py'], { languageName: 'python' }); +hljs.registerAliases(['html'], { languageName: 'xml' }); +hljs.registerAliases(['yml'], { languageName: 'yaml' }); +hljs.registerAliases(['toml', 'cfg', 'conf'], { languageName: 'ini' }); +hljs.registerAliases(['rs'], { languageName: 'rust' }); + +/** + * Language map for rehype-highlight (used in ChatMessage.tsx). + * rehype-highlight uses lowlight internally and accepts a `languages` record. + */ +export const rehypeHighlightLanguages: Record = { + bash, css, diff, dockerfile, go, ini, javascript, json, + markdown, python, rust, shell, sql, typescript, xml, yaml, +}; + +/** + * rehype-highlight options with our custom language subset. + */ +export const rehypeHighlightOptions = { + languages: rehypeHighlightLanguages, + aliases: { + bash: ['sh', 'zsh'], + javascript: ['js', 'jsx'], + typescript: ['ts', 'tsx'], + python: ['py'], + xml: ['html'], + yaml: ['yml'], + ini: ['toml', 'cfg', 'conf'], + rust: ['rs'], + }, +} as const; + +export default hljs;