feat(problem-editor): add LSP support and language client connection

This commit is contained in:
cfngc4594 2025-03-23 18:50:07 +08:00
parent becb48f4d7
commit 4842c9302c

View File

@ -7,6 +7,9 @@ import { Loading } from "@/components/loading";
import { shikiToMonaco } from "@shikijs/monaco";
import { useProblem } from "@/hooks/use-problem";
import type { Monaco } from "@monaco-editor/react";
import { useCallback, useEffect, useRef } from "react";
import { connectToLanguageServer } from "@/lib/language-server";
import type { MonacoLanguageClient } from "monaco-languageclient";
import { DefaultEditorOptionConfig } from "@/config/editor-option";
// Dynamically import Monaco Editor with SSR disabled
@ -25,14 +28,81 @@ const Editor = dynamic(
);
export function CodeEditor() {
const { setEditor, currentLang, currentPath, currentTheme, currentValue, changeValue } = useProblem();
const {
hydrated,
editor,
setEditor,
setMonacoLanguageClient,
currentLang,
currentPath,
currentTheme,
currentValue,
changeValue,
currentEditorLanguageConfig,
currentLanguageServerConfig,
} = useProblem();
const monacoLanguageClientRef = useRef<MonacoLanguageClient | null>(null);
// Connect to LSP only if enabled
const connectLSP = useCallback(async () => {
if (!(currentLang && editor)) return;
// If there's an existing language client, stop it first
if (monacoLanguageClientRef.current) {
monacoLanguageClientRef.current.stop();
monacoLanguageClientRef.current = null;
setMonacoLanguageClient(null);
}
if (!currentEditorLanguageConfig || !currentLanguageServerConfig) return;
// Create a new language client
try {
const monacoLanguageClient = await connectToLanguageServer(
currentEditorLanguageConfig,
currentLanguageServerConfig,
);
monacoLanguageClientRef.current = monacoLanguageClient;
setMonacoLanguageClient(monacoLanguageClient);
} catch (error) {
console.error("Failed to connect to LSP:", error);
}
}, [
currentEditorLanguageConfig,
currentLang,
currentLanguageServerConfig,
editor,
setMonacoLanguageClient,
]);
// Reconnect to the LSP whenever language or lspConfig changes
useEffect(() => {
connectLSP();
}, [connectLSP]);
// Cleanup the LSP connection when the component unmounts
useEffect(() => {
return () => {
if (monacoLanguageClientRef.current) {
monacoLanguageClientRef.current.stop();
monacoLanguageClientRef.current = null;
setMonacoLanguageClient(null);
}
};
}, [setMonacoLanguageClient]);
if (!hydrated) {
return <Loading />;
}
const handleBeforeMount = (monaco: Monaco) => {
shikiToMonaco(highlighter, monaco);
};
const handleOnMount = (editor: editor.IStandaloneCodeEditor) => {
const handleOnMount = async (editor: editor.IStandaloneCodeEditor) => {
setEditor(editor);
await connectLSP();
};
const handleOnChange = (value: string | undefined) => {