mirror of
https://litchi.icu/ngc2207/judge.git
synced 2025-05-18 22:37:11 +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";
|
"use client";
|
||||||
|
|
||||||
import * as monaco from "monaco-editor";
|
import * as monaco from "monaco-editor";
|
||||||
|
import { connectToLanguageServer } from "@/lib/lsp";
|
||||||
import { useEffect, useRef, useState } from "react";
|
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 { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||||
import { COriginal, CplusplusOriginal, JavaOriginal } from "devicons-react";
|
import { COriginal, CplusplusOriginal, JavaOriginal } from "devicons-react";
|
||||||
@ -39,10 +41,14 @@ int main() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
loader.config({ monaco });
|
||||||
|
|
||||||
export default function PlaygroundPage() {
|
export default function PlaygroundPage() {
|
||||||
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
|
const [language, setLanguage] = useState<string>("c");
|
||||||
const [language, setLanguage] = useState<keyof typeof files>("c");
|
|
||||||
const file = files[language];
|
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(() => {
|
useEffect(() => {
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
@ -55,6 +61,15 @@ export default function PlaygroundPage() {
|
|||||||
column: lastLineLength + 1,
|
column: lastLineLength + 1,
|
||||||
});
|
});
|
||||||
editorRef.current.focus();
|
editorRef.current.focus();
|
||||||
|
if (webSocketRef.current) {
|
||||||
|
webSocketRef.current.close();
|
||||||
|
webSocketRef.current = null;
|
||||||
|
}
|
||||||
|
connectToLanguageServer(language, webSocketRef).then(
|
||||||
|
(languageClient) => {
|
||||||
|
languageClientRef.current = languageClient;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [language]);
|
}, [language]);
|
||||||
@ -127,6 +142,11 @@ export default function PlaygroundPage() {
|
|||||||
column: lastLineLength + 1,
|
column: lastLineLength + 1,
|
||||||
});
|
});
|
||||||
editorRef.current.focus();
|
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