diff --git a/src/components/problem-editor.tsx b/src/components/problem-editor.tsx index 4a118bd..55ba9d7 100644 --- a/src/components/problem-editor.tsx +++ b/src/components/problem-editor.tsx @@ -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(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 ; + } 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) => {