From 0c1ecbcff2c84e37b26abc194eb1eb21bb05d563 Mon Sep 17 00:00:00 2001 From: cfngc4594 Date: Tue, 4 Mar 2025 21:05:23 +0800 Subject: [PATCH] feat(editor): initialize CoreEditorLsp component --- src/components/core-editor-lsp.tsx | 118 +++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 src/components/core-editor-lsp.tsx diff --git a/src/components/core-editor-lsp.tsx b/src/components/core-editor-lsp.tsx new file mode 100644 index 0000000..b2205da --- /dev/null +++ b/src/components/core-editor-lsp.tsx @@ -0,0 +1,118 @@ +"use client"; + +import dynamic from "next/dynamic"; +import { Skeleton } from "./ui/skeleton"; +import { highlighter } from "@/lib/shiki"; +import type { editor } from "monaco-editor"; +import { shikiToMonaco } from "@shikijs/monaco"; +import type { Monaco } from "@monaco-editor/react"; +import { useCallback, useEffect, useRef } from "react"; +import { connectToLanguageServer } from "@/lib/language-server"; +import { LanguageServerMetadata } from "@/types/language-server"; +import type { MonacoLanguageClient } from "monaco-languageclient"; + +const Editor = dynamic( + async () => { + await import("vscode"); + const monaco = await import("monaco-editor"); + const { loader } = await import("@monaco-editor/react"); + loader.config({ monaco }); + return (await import("@monaco-editor/react")).Editor; + }, + { + ssr: false, + loading: () => + } +); + +interface CoreEditorLspProps { + language?: string; + theme?: string; + path?: string; + value?: string; + className?: string; + lspConfig?: LanguageServerMetadata; + editorConfig?: editor.IEditorConstructionOptions; + enableLSP?: boolean; +} + +export default function CoreEditorLsp({ + language, + theme, + path, + value, + className, + lspConfig, + editorConfig, + enableLSP = true, +}: CoreEditorLspProps) { + const editorRef = useRef(null); + const monacoLanguageClientRef = useRef(null); + + // Connect to LSP only if enabled + const connectLSP = useCallback(async () => { + if (!enableLSP || !language || !lspConfig || !editorRef.current) return; + + // If there's an existing language client, stop it first + if (monacoLanguageClientRef.current) { + monacoLanguageClientRef.current.stop(); + monacoLanguageClientRef.current = null; + } + + // Create a new language client + try { + const monacoLanguageClient = await connectToLanguageServer( + lspConfig.protocol, + lspConfig.hostname, + lspConfig.port, + lspConfig.path, + lspConfig.lang + ); + monacoLanguageClientRef.current = monacoLanguageClient; + } catch (error) { + console.error("Failed to connect to LSP:", error); + } + }, [language, lspConfig, enableLSP]); + + // Connect to LSP once the editor has mounted + const handleEditorDidMount = useCallback( + async (editor: editor.IStandaloneCodeEditor) => { + editorRef.current = editor; + await connectLSP(); + }, + [connectLSP] + ); + + // Reconnect to the LSP whenever language or lspConfig changes + useEffect(() => { + connectLSP(); + }, [lspConfig, language, connectLSP]); + + // Cleanup the LSP connection when the component unmounts + useEffect(() => { + return () => { + if (monacoLanguageClientRef.current) { + monacoLanguageClientRef.current.stop(); + monacoLanguageClientRef.current = null; + } + }; + }, []); + + function handleEditorWillMount(monaco: Monaco) { + shikiToMonaco(highlighter, monaco); + } + + return ( + } + /> + ); +}