diff --git a/src/renderer/src/assets/styles/markdown.scss b/src/renderer/src/assets/styles/markdown.scss index 9be43898c9..e71e45f1aa 100644 --- a/src/renderer/src/assets/styles/markdown.scss +++ b/src/renderer/src/assets/styles/markdown.scss @@ -98,10 +98,6 @@ white-space: pre; } - code { - font-family: 'Courier New', Courier, monospace; - } - p code, li code { background: var(--color-background-mute); diff --git a/src/renderer/src/context/SyntaxHighlighterProvider.tsx b/src/renderer/src/context/SyntaxHighlighterProvider.tsx index b2dd13db0a..11e5cac5c2 100644 --- a/src/renderer/src/context/SyntaxHighlighterProvider.tsx +++ b/src/renderer/src/context/SyntaxHighlighterProvider.tsx @@ -13,7 +13,7 @@ import { } from 'shiki' interface SyntaxHighlighterContextType { - codeToHtml: (code: string, language: string) => string + codeToHtml: (code: string, language: string) => Promise } const SyntaxHighlighterContext = createContext(undefined) @@ -34,11 +34,10 @@ export const SyntaxHighlighterProvider: React.FC = ({ childre useEffect(() => { const initMermaid = async () => { if (!window.mermaid) { - await loadScript('https://unpkg.com/mermaid@10.9.1/dist/mermaid.min.js') + await loadScript('https://unpkg.com/mermaid@11.4.0/dist/mermaid.min.js') window.mermaid.initialize({ startOnLoad: true, - theme: theme === ThemeMode.dark ? 'dark' : 'default', - securityLevel: 'loose' + theme: theme === ThemeMode.dark ? 'dark' : 'default' }) window.mermaid.contentLoaded() } @@ -49,31 +48,49 @@ export const SyntaxHighlighterProvider: React.FC = ({ childre useEffect(() => { const initHighlighter = async () => { + const commonLanguages = ['javascript', 'typescript', 'python', 'java', 'markdown'] + const hl = await createHighlighter({ - themes: Object.keys(bundledThemes), - langs: Object.keys(bundledLanguages) + themes: [highlighterTheme], + langs: commonLanguages }) + setHighlighter(hl) + + window.requestIdleCallback( + () => { + hl.loadTheme(...(Object.keys(bundledThemes) as BundledTheme[])) + hl.loadLanguage(...(Object.keys(bundledLanguages) as BundledLanguage[])) + }, + { timeout: 2000 } + ) } initHighlighter() - }, []) + }, [highlighterTheme, theme]) - const codeToHtml = (code: string, language: string) => { + const codeToHtml = async (code: string, language: string) => { if (!highlighter) return '' - return highlighter.codeToHtml(code, { - lang: language, - theme: highlighterTheme, - transformers: [ - { - preprocess(code) { - if (code.endsWith('\n')) code = code.slice(0, -1) - return code - } + try { + if (!highlighter.getLoadedLanguages().includes(language as BundledLanguage)) { + if (language in bundledLanguages) { + await highlighter.loadLanguage(language as BundledLanguage) + console.log(`Loaded language: ${language}`) + } else { + console.warn(`Language '${language}' is not supported`) + return `
${code}
` } - ] - }) + } + + return highlighter.codeToHtml(code, { + lang: language, + theme: highlighterTheme + }) + } catch (error) { + console.warn(`Error highlighting code for language '${language}':`, error) + return `
${code}
` + } } return {children} diff --git a/src/renderer/src/pages/home/Markdown/CodeBlock.tsx b/src/renderer/src/pages/home/Markdown/CodeBlock.tsx index 304a207cea..d814632446 100644 --- a/src/renderer/src/pages/home/Markdown/CodeBlock.tsx +++ b/src/renderer/src/pages/home/Markdown/CodeBlock.tsx @@ -2,7 +2,7 @@ import { CheckOutlined } from '@ant-design/icons' import CopyIcon from '@renderer/components/Icons/CopyIcon' import { useSyntaxHighlighter } from '@renderer/context/SyntaxHighlighterProvider' import { useSettings } from '@renderer/hooks/useSettings' -import React, { memo, useState } from 'react' +import React, { memo, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -20,10 +20,16 @@ const CodeBlock: React.FC = ({ children, className }) => { const showFooterCopyButton = children && children.length > 500 const { codeShowLineNumbers, fontSize } = useSettings() const language = match?.[1] ?? 'text' - + const [html, setHtml] = useState('') const { codeToHtml } = useSyntaxHighlighter() - const html = codeToHtml(children, language) + useEffect(() => { + const loadHighlightedCode = async () => { + const highlightedHtml = await codeToHtml(children, language) + setHtml(highlightedHtml) + } + loadHighlightedCode() + }, [children, language, codeToHtml]) if (language === 'mermaid') { return