mirror of
https://litchi.icu/ngc2207/judge.git
synced 2025-05-18 20:56:33 +00:00
feat: integrate language server support with WebSocket connection for C/C++ languages
This commit is contained in:
parent
104e66d4d0
commit
937330ac3d
Binary file not shown.
@ -18,10 +18,15 @@
|
||||
"clsx": "^2.1.1",
|
||||
"devicons-react": "^1.4.0",
|
||||
"lucide-react": "^0.469.0",
|
||||
"monaco-editor": "0.36.1",
|
||||
"monaco-languageclient": "5.0.1",
|
||||
"normalize-url": "~8.0.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"vscode-languageclient": "~8.1.0",
|
||||
"vscode-ws-jsonrpc": "3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.17.0",
|
||||
|
@ -3,19 +3,38 @@ import {
|
||||
DEFAULT_EDITOR_THEME,
|
||||
DEFAULT_EDITOR_LANGUAGE,
|
||||
} from "@/config";
|
||||
import { useState } from "react";
|
||||
import * as monaco from "monaco-editor";
|
||||
import { highlighter } from "@/lib/shiki";
|
||||
import { Bot, CodeXml } from "lucide-react";
|
||||
import { shikiToMonaco } from "@shikijs/monaco";
|
||||
import { DiffEditor, Editor, Monaco } from "@monaco-editor/react";
|
||||
import { connectToLanguageServer } from "@/lib/lsp";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||
import { DiffEditor, Editor, Monaco, loader } from "@monaco-editor/react";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
|
||||
loader.config({ monaco });
|
||||
|
||||
function App() {
|
||||
const [language, setLanguage] = useState(DEFAULT_EDITOR_LANGUAGE);
|
||||
const [theme, setTheme] = useState(DEFAULT_EDITOR_THEME);
|
||||
const file = DEFAULT_FILES[language];
|
||||
const webSocketRef = useRef<WebSocket | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (webSocketRef.current) {
|
||||
webSocketRef.current.close();
|
||||
}
|
||||
connectToLanguageServer(language).then((webSocket) => {
|
||||
webSocketRef.current = webSocket;
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (webSocketRef.current) {
|
||||
webSocketRef.current.close();
|
||||
}
|
||||
};
|
||||
}, [language]);
|
||||
|
||||
return (
|
||||
<div className="h-screen bg-[#282c34] dark overflow-hidden">
|
||||
@ -71,10 +90,7 @@ function App() {
|
||||
beforeMount={async (monaco: Monaco) => {
|
||||
shikiToMonaco(await highlighter, monaco);
|
||||
}}
|
||||
onMount={(
|
||||
editor: monaco.editor.IStandaloneCodeEditor,
|
||||
monaco: Monaco
|
||||
) => {
|
||||
onMount={(editor: monaco.editor.IStandaloneCodeEditor) => {
|
||||
const value = editor.getModel()?.getValue();
|
||||
if (value !== undefined) {
|
||||
window.parent.postMessage(
|
||||
@ -82,6 +98,9 @@ function App() {
|
||||
"*"
|
||||
);
|
||||
}
|
||||
connectToLanguageServer(language).then((webSocket) => {
|
||||
webSocketRef.current = webSocket;
|
||||
});
|
||||
}}
|
||||
onChange={(value) => {
|
||||
if (value !== undefined) {
|
||||
|
82
code-editor/src/lib/lsp.ts
Normal file
82
code-editor/src/lib/lsp.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import {
|
||||
toSocket,
|
||||
WebSocketMessageReader,
|
||||
WebSocketMessageWriter,
|
||||
} from "vscode-ws-jsonrpc";
|
||||
import {
|
||||
CloseAction,
|
||||
ErrorAction,
|
||||
MessageTransports,
|
||||
} from "vscode-languageclient";
|
||||
import normalizeUrl from "normalize-url";
|
||||
import { MonacoLanguageClient } from "monaco-languageclient";
|
||||
|
||||
export const SUPPORTED_LSP_LANGUAGES: {
|
||||
[key: string]: { hostname: string; port: number | null; path: string };
|
||||
} = {
|
||||
c: {
|
||||
hostname: "c.litchi.icu",
|
||||
port: null,
|
||||
path: "/clangd",
|
||||
},
|
||||
cpp: {
|
||||
hostname: "cpp.litchi.icu",
|
||||
port: null,
|
||||
path: "/clangd",
|
||||
},
|
||||
};
|
||||
|
||||
function createUrl(
|
||||
hostname: string,
|
||||
port: number | null,
|
||||
path: string
|
||||
): string {
|
||||
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
||||
return port !== null
|
||||
? normalizeUrl(`${protocol}://${hostname}:${port}${path}`)
|
||||
: normalizeUrl(`${protocol}://${hostname}${path}`);
|
||||
}
|
||||
|
||||
function createLanguageClient(
|
||||
transports: MessageTransports
|
||||
): MonacoLanguageClient {
|
||||
return new MonacoLanguageClient({
|
||||
name: "Judge4c Language Client",
|
||||
clientOptions: {
|
||||
documentSelector: ["c", "cpp"],
|
||||
errorHandler: {
|
||||
error: () => ({ action: ErrorAction.Continue }),
|
||||
closed: () => ({ action: CloseAction.DoNotRestart }),
|
||||
},
|
||||
},
|
||||
connectionProvider: {
|
||||
get: () => {
|
||||
return Promise.resolve(transports);
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function createWebSocket(url: string) {
|
||||
const webSocket = new WebSocket(url);
|
||||
webSocket.onopen = () => {
|
||||
const socket = toSocket(webSocket);
|
||||
const reader = new WebSocketMessageReader(socket);
|
||||
const writer = new WebSocketMessageWriter(socket);
|
||||
const languageClient = createLanguageClient({
|
||||
reader,
|
||||
writer,
|
||||
});
|
||||
languageClient.start();
|
||||
reader.onClose(() => languageClient.stop());
|
||||
};
|
||||
return webSocket;
|
||||
}
|
||||
|
||||
export async function connectToLanguageServer(
|
||||
language: string
|
||||
): Promise<WebSocket> {
|
||||
const { hostname, port, path } = SUPPORTED_LSP_LANGUAGES[language];
|
||||
const url = createUrl(hostname, port, path);
|
||||
return createWebSocket(url);
|
||||
}
|
Loading…
Reference in New Issue
Block a user