mirror of
https://litchi.icu/ngc2207/judge.git
synced 2025-05-18 19:47:14 +00:00
feat(playground): integrate language server support with WebSocket connection handling
This commit is contained in:
parent
0bc5758d44
commit
168facb85b
@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import * as monaco from "monaco-editor";
|
||||
import { connectToLanguageServer } from "@/lib/lsp";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Editor } from "@monaco-editor/react";
|
||||
import { Editor, loader } from "@monaco-editor/react";
|
||||
import { MonacoLanguageClient } from "monaco-languageclient";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||
import { COriginal, CplusplusOriginal, JavaOriginal } from "devicons-react";
|
||||
@ -39,10 +41,14 @@ int main() {
|
||||
},
|
||||
};
|
||||
|
||||
loader.config({ monaco });
|
||||
|
||||
export default function PlaygroundPage() {
|
||||
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
|
||||
const [language, setLanguage] = useState<keyof typeof files>("c");
|
||||
const [language, setLanguage] = useState<string>("c");
|
||||
const file = files[language];
|
||||
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
|
||||
const webSocketRef = useRef<WebSocket | null>(null);
|
||||
const languageClientRef = useRef<MonacoLanguageClient | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (editorRef.current) {
|
||||
@ -55,6 +61,15 @@ export default function PlaygroundPage() {
|
||||
column: lastLineLength + 1,
|
||||
});
|
||||
editorRef.current.focus();
|
||||
if (webSocketRef.current) {
|
||||
webSocketRef.current.close();
|
||||
webSocketRef.current = null;
|
||||
}
|
||||
connectToLanguageServer(language, webSocketRef).then(
|
||||
(languageClient) => {
|
||||
languageClientRef.current = languageClient;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [language]);
|
||||
@ -127,6 +142,11 @@ export default function PlaygroundPage() {
|
||||
column: lastLineLength + 1,
|
||||
});
|
||||
editorRef.current.focus();
|
||||
connectToLanguageServer(language, webSocketRef).then(
|
||||
(languageClient) => {
|
||||
languageClientRef.current = languageClient;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
94
src/lib/lsp.ts
Normal file
94
src/lib/lsp.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import {
|
||||
toSocket,
|
||||
WebSocketMessageReader,
|
||||
WebSocketMessageWriter,
|
||||
} from "vscode-ws-jsonrpc";
|
||||
import {
|
||||
CloseAction,
|
||||
ErrorAction,
|
||||
MessageTransports,
|
||||
} from "vscode-languageclient";
|
||||
import { RefObject } from "react";
|
||||
import normalizeUrl from "normalize-url";
|
||||
import { MonacoLanguageClient } from "monaco-languageclient";
|
||||
|
||||
const LSP_SUPPORTED_LANGUAGES: {
|
||||
[key: string]: { hostname: string; port: number; path: string };
|
||||
} = {
|
||||
c: {
|
||||
hostname: "localhost",
|
||||
port: 30001,
|
||||
path: "/clangd",
|
||||
},
|
||||
cpp: {
|
||||
hostname: "localhost",
|
||||
port: 30002,
|
||||
path: "/clangd",
|
||||
},
|
||||
};
|
||||
|
||||
function createUrl(hostname: string, port: number, path: string): string {
|
||||
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
||||
return normalizeUrl(`${protocol}://${hostname}:${port}${path}`);
|
||||
}
|
||||
|
||||
const languageClientConfig = {
|
||||
name: "Language Client",
|
||||
clientOptions: {
|
||||
documentSelector: ["c", "cpp"],
|
||||
errorHandler: {
|
||||
error: () => ({ action: ErrorAction.Continue }),
|
||||
closed: () => ({ action: CloseAction.DoNotRestart }),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function createLanguageClient(
|
||||
transports: MessageTransports
|
||||
): MonacoLanguageClient {
|
||||
return new MonacoLanguageClient({
|
||||
...languageClientConfig,
|
||||
connectionProvider: {
|
||||
get: () => Promise.resolve(transports),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function connectToLanguageServer(
|
||||
language: string,
|
||||
webSocketRef: RefObject<WebSocket | null>
|
||||
): Promise<MonacoLanguageClient> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let url: string;
|
||||
if (language in LSP_SUPPORTED_LANGUAGES) {
|
||||
const { hostname, port, path } = LSP_SUPPORTED_LANGUAGES[language];
|
||||
url = createUrl(hostname, port, path);
|
||||
} else {
|
||||
reject(new Error("Unsupported language"));
|
||||
return;
|
||||
}
|
||||
|
||||
const webSocket = new WebSocket(url);
|
||||
webSocketRef.current = webSocket;
|
||||
|
||||
webSocket.onopen = () => {
|
||||
console.log("WebSocket connection opened successfully.");
|
||||
const socket = toSocket(webSocket);
|
||||
const reader = new WebSocketMessageReader(socket);
|
||||
const writer = new WebSocketMessageWriter(socket);
|
||||
const languageClient = createLanguageClient({ reader, writer });
|
||||
languageClient.start();
|
||||
resolve(languageClient);
|
||||
};
|
||||
|
||||
webSocket.onclose = () => {
|
||||
console.log("WebSocket connection closed.");
|
||||
reject(new Error("WebSocket connection closed unexpectedly."));
|
||||
};
|
||||
|
||||
webSocket.onerror = (error) => {
|
||||
console.error("WebSocket connection error:", error);
|
||||
reject(new Error(`WebSocket connection error: ${error}`));
|
||||
};
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user