2026-02-01 20:53:00 +02:00
|
|
|
import React, { useMemo, useEffect } from 'react';
|
2025-12-14 02:29:46 +02:00
|
|
|
import { WorkerPoolContextProvider, useWorkerPool } from '@pierre/diffs/react';
|
|
|
|
|
import type { SupportedLanguages } from '@pierre/diffs';
|
|
|
|
|
|
|
|
|
|
import { useOptionalThemeSystem } from './useThemeSystem';
|
|
|
|
|
import { workerFactory } from '@/lib/diff/workerFactory';
|
2026-02-01 18:29:34 +02:00
|
|
|
import { ensurePierreThemeRegistered } from '@/lib/shiki/appThemeRegistry';
|
|
|
|
|
import { getDefaultTheme } from '@/lib/theme/themes';
|
2026-02-01 20:53:00 +02:00
|
|
|
// NOTE: keep provider lightweight; avoid main-thread diff parsing here.
|
2025-12-14 02:29:46 +02:00
|
|
|
|
2025-12-17 16:16:28 +02:00
|
|
|
// Preload common languages for faster initial diff rendering
|
2025-12-14 02:29:46 +02:00
|
|
|
const PRELOAD_LANGS: SupportedLanguages[] = [
|
2026-02-01 20:53:00 +02:00
|
|
|
// Keep small; workers load others on-demand.
|
2025-12-14 02:29:46 +02:00
|
|
|
'typescript',
|
|
|
|
|
'javascript',
|
|
|
|
|
'tsx',
|
2025-12-17 16:16:28 +02:00
|
|
|
'jsx',
|
2025-12-14 02:29:46 +02:00
|
|
|
'json',
|
2025-12-17 16:16:28 +02:00
|
|
|
'markdown',
|
2025-12-14 02:29:46 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
interface DiffWorkerProviderProps {
|
|
|
|
|
children: React.ReactNode;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 16:16:28 +02:00
|
|
|
// Component that warms up the worker pool and precomputes diff ASTs
|
2026-02-01 18:29:34 +02:00
|
|
|
const WorkerPoolWarmup: React.FC<{
|
|
|
|
|
children: React.ReactNode;
|
|
|
|
|
renderTheme: { light: string; dark: string };
|
2026-02-01 20:53:00 +02:00
|
|
|
}> = ({ children, renderTheme }) => {
|
2025-12-17 16:16:28 +02:00
|
|
|
const workerPool = useWorkerPool();
|
2026-02-01 18:29:34 +02:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!workerPool) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Important: WorkerPoolContextProvider uses a singleton and does not react to
|
|
|
|
|
// prop changes. Update the worker pool render options explicitly.
|
2026-02-01 20:53:00 +02:00
|
|
|
// Force-disable intra-line diff globally (word-level/char-level).
|
|
|
|
|
void workerPool.setRenderOptions({ theme: renderTheme, lineDiffType: 'none' });
|
2026-02-01 18:29:34 +02:00
|
|
|
}, [renderTheme, workerPool]);
|
|
|
|
|
|
2025-12-17 16:16:28 +02:00
|
|
|
return <>{children}</>;
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-14 02:29:46 +02:00
|
|
|
export const DiffWorkerProvider: React.FC<DiffWorkerProviderProps> = ({ children }) => {
|
|
|
|
|
const themeSystem = useOptionalThemeSystem();
|
|
|
|
|
const isDark = themeSystem?.currentTheme?.metadata?.variant === 'dark';
|
|
|
|
|
|
2026-02-01 18:29:34 +02:00
|
|
|
const fallbackLight = getDefaultTheme(false);
|
|
|
|
|
const fallbackDark = getDefaultTheme(true);
|
|
|
|
|
|
|
|
|
|
const lightThemeId = themeSystem?.lightThemeId ?? fallbackLight.metadata.id;
|
|
|
|
|
const darkThemeId = themeSystem?.darkThemeId ?? fallbackDark.metadata.id;
|
|
|
|
|
|
|
|
|
|
const lightTheme =
|
|
|
|
|
themeSystem?.availableThemes.find((theme) => theme.metadata.id === lightThemeId) ??
|
|
|
|
|
fallbackLight;
|
|
|
|
|
const darkTheme =
|
|
|
|
|
themeSystem?.availableThemes.find((theme) => theme.metadata.id === darkThemeId) ??
|
|
|
|
|
fallbackDark;
|
|
|
|
|
|
|
|
|
|
ensurePierreThemeRegistered(lightTheme);
|
|
|
|
|
ensurePierreThemeRegistered(darkTheme);
|
2025-12-15 00:20:26 +02:00
|
|
|
|
2025-12-14 02:29:46 +02:00
|
|
|
const highlighterOptions = useMemo(() => ({
|
|
|
|
|
theme: {
|
2026-02-01 18:29:34 +02:00
|
|
|
dark: darkTheme.metadata.id,
|
|
|
|
|
light: lightTheme.metadata.id,
|
2025-12-14 02:29:46 +02:00
|
|
|
},
|
|
|
|
|
themeType: isDark ? ('dark' as const) : ('light' as const),
|
|
|
|
|
langs: PRELOAD_LANGS,
|
2026-02-01 18:29:34 +02:00
|
|
|
}), [darkTheme.metadata.id, isDark, lightTheme.metadata.id]);
|
|
|
|
|
|
|
|
|
|
const renderTheme = useMemo(
|
|
|
|
|
() => ({
|
|
|
|
|
light: lightTheme.metadata.id,
|
|
|
|
|
dark: darkTheme.metadata.id,
|
|
|
|
|
}),
|
|
|
|
|
[darkTheme.metadata.id, lightTheme.metadata.id],
|
|
|
|
|
);
|
2025-12-14 02:29:46 +02:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<WorkerPoolContextProvider
|
|
|
|
|
poolOptions={{
|
|
|
|
|
workerFactory,
|
2026-01-28 12:29:01 +02:00
|
|
|
poolSize: 2,
|
|
|
|
|
totalASTLRUCacheSize: 50,
|
2025-12-14 02:29:46 +02:00
|
|
|
}}
|
|
|
|
|
highlighterOptions={highlighterOptions}
|
|
|
|
|
>
|
2026-02-01 18:29:34 +02:00
|
|
|
<WorkerPoolWarmup
|
|
|
|
|
renderTheme={renderTheme}
|
|
|
|
|
>
|
2025-12-17 16:16:28 +02:00
|
|
|
{children}
|
|
|
|
|
</WorkerPoolWarmup>
|
2025-12-14 02:29:46 +02:00
|
|
|
</WorkerPoolContextProvider>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-14 02:34:15 +02:00
|
|
|
// eslint-disable-next-line react-refresh/only-export-components
|
2025-12-14 02:29:46 +02:00
|
|
|
export { useWorkerPool };
|