Files
cherry-studio/src/renderer/src/context/SyntaxHighlighterProvider.tsx
T
MyPrototypeWhat 48670ff0c8 Perf/optimize rendering (#3923)
* optimize useMessageOperations

* chore: update dependencies and refactor React imports

- Added @ant-design/v5-patch-for-react-19 and rc-virtual-list to package.json.
- Updated React and ReactDOM types to version 19 in package.json and yarn.lock.
- Refactored ReactDOM usage to createRoot in main.tsx for better compatibility with React 18+.
- Changed useContext to use in SyntaxHighlighterProvider and ThemeProvider components.
- Adjusted flex-direction in Messages components to column for improved layout.
- Removed unused state in CodeBlock component.

* refactor(Messages): enhance scrolling behavior and introduce scroll utilities

- Added createScrollHandler and scrollToBottom utilities for improved scroll management.
- Updated Messages component to utilize new scroll utilities for better user experience.
- Refactored scroll handling logic to ensure smooth scrolling when new messages are added.
- Changed containerRef type to HTMLElement for better type safety.

* refactor(Messages): streamline message handling and introduce useTopicMessages hook

- Removed direct message selection from useMessageOperations and created a new useTopicMessages hook for better separation of concerns.
- Updated Messages component to utilize the new useTopicMessages hook for fetching messages.
- Enhanced message display logic with computeDisplayMessages function for improved message rendering.
- Refactored scrolling behavior to maintain a smooth user experience during message updates.

* refactor(Message Operations): introduce useTopicLoading hook for improved loading state management

- Removed loading state from useMessageOperations and created a new useTopicLoading hook for better separation of concerns.
- Updated components to utilize the new useTopicLoading hook for fetching loading states related to topics.
- Enhanced code organization and readability by streamlining message operations and loading state handling.

* refactor(Messages): replace updateMessage with updateMessageThunk for improved async handling

- Updated useMessageOperations and MessageAnchorLine components to utilize updateMessageThunk for message updates.
- Enhanced error handling and database synchronization in the new thunk implementation.
- Streamlined message update logic to improve code clarity and maintainability.

* refactor(SyntaxHighlighterProvider, MessageTools, AddMcpServerPopup): update styles and improve type safety

- Changed import statements to use TypeScript's type imports for better clarity and type safety.
- Updated MessageTools and AddMcpServerPopup components to replace bodyStyle with styles prop for consistent styling approach.
- Enhanced overall code organization and maintainability by adhering to TypeScript best practices.

* refactor(Messages): update layout and remove unnecessary prop

- Removed the hasChildren prop from the Messages component for cleaner code.
- Adjusted flex-direction in the mini chat Messages component to column-reverse for improved layout consistency.

* refactor: enhance type safety and component return types

- Updated functional components to return React.ReactElement instead of JSX.Element for better type consistency.
- Changed import statements to use TypeScript's type imports for improved clarity.
- Initialized useRef hooks with null for better type safety in various components.
- Adjusted props types to use HTMLAttributes for more accurate type definitions.

* chore: update package dependencies

- Removed outdated dependencies: @agentic/exa, @agentic/searxng, @agentic/tavily, and rc-virtual-list.
- Added back @ant-design/v5-patch-for-react-19 and rc-virtual-list with specified versions for improved compatibility.

* fix(useMessageOperations): ensure message retrieval from store when updating content
2025-03-27 12:06:47 +08:00

97 lines
3.4 KiB
TypeScript

import { useTheme } from '@renderer/context/ThemeProvider'
import { useMermaid } from '@renderer/hooks/useMermaid'
import { useSettings } from '@renderer/hooks/useSettings'
import { type CodeStyleVarious, ThemeMode } from '@renderer/types'
import type React from 'react'
import { createContext, type PropsWithChildren, use, useCallback, useEffect, useMemo, useState } from 'react'
import type { BundledLanguage, BundledTheme, HighlighterGeneric } from 'shiki'
import { bundledLanguages, bundledThemes, createHighlighter } from 'shiki'
interface SyntaxHighlighterContextType {
codeToHtml: (code: string, language: string) => Promise<string>
}
const SyntaxHighlighterContext = createContext<SyntaxHighlighterContextType | undefined>(undefined)
export const SyntaxHighlighterProvider: React.FC<PropsWithChildren> = ({ children }) => {
const { theme } = useTheme()
const [highlighter, setHighlighter] = useState<HighlighterGeneric<BundledLanguage, BundledTheme> | null>(null)
const { codeStyle } = useSettings()
useMermaid()
const highlighterTheme = useMemo(() => {
if (!codeStyle || codeStyle === 'auto') {
return theme === ThemeMode.light ? 'one-light' : 'material-theme-darker'
}
return codeStyle
}, [theme, codeStyle])
useEffect(() => {
const initHighlighter = async () => {
const commonLanguages = ['javascript', 'typescript', 'python', 'java', 'markdown']
const hl = await createHighlighter({
themes: [highlighterTheme],
langs: commonLanguages
})
setHighlighter(hl)
// Load all themes and languages
// hl.loadTheme(...(Object.keys(bundledThemes) as BundledTheme[]))
// hl.loadLanguage(...(Object.keys(bundledLanguages) as BundledLanguage[]))
}
initHighlighter()
}, [highlighterTheme])
const codeToHtml = useCallback(
async (_code: string, language: string) => {
{
if (!highlighter) return ''
const languageMap: Record<string, string> = {
vab: 'vb'
}
const mappedLanguage = languageMap[language] || language
const code = _code?.trimEnd() ?? ''
const escapedCode = code?.replace(/[<>]/g, (char) => ({ '<': '&lt;', '>': '&gt;' })[char]!)
try {
if (!highlighter.getLoadedLanguages().includes(mappedLanguage as BundledLanguage)) {
if (mappedLanguage in bundledLanguages || mappedLanguage === 'text') {
await highlighter.loadLanguage(mappedLanguage as BundledLanguage)
} else {
return `<pre style="padding: 10px"><code>${escapedCode}</code></pre>`
}
}
return highlighter.codeToHtml(code, {
lang: mappedLanguage,
theme: highlighterTheme
})
} catch (error) {
console.warn(`Error highlighting code for language '${mappedLanguage}':`, error)
return `<pre style="padding: 10px"><code>${escapedCode}</code></pre>`
}
}
},
[highlighter, highlighterTheme]
)
return <SyntaxHighlighterContext.Provider value={{ codeToHtml }}>{children}</SyntaxHighlighterContext.Provider>
}
export const useSyntaxHighlighter = () => {
const context = use(SyntaxHighlighterContext)
if (!context) {
throw new Error('useSyntaxHighlighter must be used within a SyntaxHighlighterProvider')
}
return context
}
export const codeThemes = ['auto', ...Object.keys(bundledThemes)] as CodeStyleVarious[]