feat(code-editor): enhance language client integration with dynamic server configuration

This commit is contained in:
cfngc4594 2025-02-23 13:55:37 +08:00
parent 62149db922
commit 9e1bca2cce

View File

@ -10,6 +10,7 @@ import { shikiToMonaco } from "@shikijs/monaco";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { useCodeEditorState } from "@/store/useCodeEditor"; import { useCodeEditorState } from "@/store/useCodeEditor";
import { CODE_EDITOR_OPTIONS } from "@/constants/code-editor-options"; import { CODE_EDITOR_OPTIONS } from "@/constants/code-editor-options";
import { SUPPORTED_LANGUAGE_SERVERS } from "@/config/language-server";
import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from "vscode-ws-jsonrpc"; import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from "vscode-ws-jsonrpc";
const Editor = dynamic( const Editor = dynamic(
@ -30,51 +31,62 @@ const Editor = dynamic(
export default function CodeEditor() { export default function CodeEditor() {
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
const { language } = useCodeEditorState(); const { language, languageClient, setLanguageClient } = useCodeEditorState();
useEffect(() => { useEffect(() => {
const lspUrl = process.env.NEXT_PUBLIC_LSP_C_URL || "ws://localhost:4594/clangd"; if (languageClient) {
const url = normalizeUrl(lspUrl); languageClient.dispose();
const webSocket = new WebSocket(url); setLanguageClient(null);
}
webSocket.onopen = async () => { const serverConfig = SUPPORTED_LANGUAGE_SERVERS.find((s) => s.id === language);
const socket = toSocket(webSocket);
const reader = new WebSocketMessageReader(socket);
const writer = new WebSocketMessageWriter(socket);
const { MonacoLanguageClient } = await import("monaco-languageclient"); if (serverConfig) {
const { ErrorAction, CloseAction } = await import("vscode-languageclient"); const lspUrl = `${serverConfig.protocol}://${serverConfig.hostname}${serverConfig.port ? `:${serverConfig.port}` : ''}${serverConfig.path || ''}`
const url = normalizeUrl(lspUrl);
const webSocket = new WebSocket(url);
const languageClient = new MonacoLanguageClient({ webSocket.onopen = async () => {
name: "C Language Client", const socket = toSocket(webSocket);
clientOptions: { const reader = new WebSocketMessageReader(socket);
documentSelector: ["c"], const writer = new WebSocketMessageWriter(socket);
errorHandler: {
error: () => ({ action: ErrorAction.Continue }), const { MonacoLanguageClient } = await import("monaco-languageclient");
closed: () => ({ action: CloseAction.DoNotRestart }), const { ErrorAction, CloseAction } = await import("vscode-languageclient");
const languageClient = new MonacoLanguageClient({
name: `${serverConfig.label} Language Client`,
clientOptions: {
documentSelector: [serverConfig.id],
errorHandler: {
error: () => ({ action: ErrorAction.Continue }),
closed: () => ({ action: CloseAction.DoNotRestart }),
},
}, },
}, connectionProvider: {
connectionProvider: { get: () => Promise.resolve({ reader, writer }),
get: () => Promise.resolve({ reader, writer }), },
}, });
});
languageClient.start(); languageClient.start();
reader.onClose(() => languageClient.stop()); reader.onClose(() => languageClient.stop());
};
webSocket.onerror = (event) => { setLanguageClient(languageClient);
console.error("WebSocket error observed:", event); };
};
webSocket.onclose = (event) => { webSocket.onerror = (event) => {
console.log("WebSocket closed:", event); console.error("WebSocket error observed:", event);
}; };
return () => { webSocket.onclose = (event) => {
webSocket.close(); console.log("WebSocket closed:", event);
}; };
}, []);
return () => {
webSocket.close();
};
}
}, [language]);
return ( return (
<Editor <Editor