feat(playground): integrate WebSocket support and enhance language client in code editor

This commit is contained in:
ngc2207 2024-12-17 20:59:55 +08:00
parent 1afa7a1a5d
commit f0a2010985
3 changed files with 83 additions and 1 deletions

View File

@ -2,6 +2,7 @@
"extends": ["next/core-web-vitals", "next/typescript"],
"rules": {
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/no-empty-object-type": "warn"
"@typescript-eslint/no-empty-object-type": "warn",
"@typescript-eslint/no-require-imports": "warn"
}
}

View File

@ -30,14 +30,18 @@
"gitea-js": "^1.22.0",
"jotai": "^2.10.3",
"lucide-react": "^0.468.0",
"monaco-languageclient": "^8.8.3",
"next": "15.0.4",
"next-auth": "^5.0.0-beta.25",
"next-intl": "^3.26.1",
"next-themes": "^0.4.4",
"normalize-url": "^8.0.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"reconnecting-websocket": "^4.4.0",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7",
"vscode-ws-jsonrpc": "^3.3.2",
"zustand": "^5.0.2"
},
"devDependencies": {

View File

@ -1,12 +1,27 @@
"use client";
import {
toSocket,
WebSocketMessageReader,
WebSocketMessageWriter,
} from "vscode-ws-jsonrpc";
import {
CloseAction,
ErrorAction,
MessageTransports,
} from "vscode-languageclient";
import "@fontsource-variable/fira-code";
import normalizeUrl from "normalize-url";
import { createHighlighter } from "shiki";
import type { editor } from "monaco-editor";
import { shikiToMonaco } from "@shikijs/monaco";
import { useEffect, useRef, useMemo } from "react";
import { useCodeEditorStore } from "@/store/codeEditorStore";
import { MonacoLanguageClient } from "monaco-languageclient";
import MonacoEditor, { type Monaco } from "@monaco-editor/react";
import { initServices } from "monaco-languageclient/vscode/services";
const ReconnectingWebSocket = require("reconnecting-websocket");
const ADDITIONAL_THEMES = [
"andromeeda",
@ -63,6 +78,66 @@ export function CodeEditor() {
[isMinimap, isLigature]
);
const createLanguageClient = (
transports: MessageTransports
): MonacoLanguageClient => {
return new MonacoLanguageClient({
name: "LSP Language Client",
clientOptions: {
documentSelector: ADDITIONAL_LANGUAGES,
errorHandler: {
error: () => ({ action: ErrorAction.Continue }),
closed: () => ({ action: CloseAction.DoNotRestart }),
},
},
connectionProvider: {
get: () => {
return Promise.resolve(transports);
},
},
});
};
useEffect(() => {
if (!monacoRef.current) return;
const url = normalizeUrl(`ws://172.20.0.13:3000`);
const socketOptions = {
maxReconnectionDelay: 10000,
minReconnectionDelay: 1000,
reconnectionDelayGrowFactor: 1.3,
connectionTimeout: 10000,
maxRetries: Infinity,
debug: true,
};
const webSocket: WebSocket = new ReconnectingWebSocket.default(
url,
[],
socketOptions
);
webSocket.onopen = () => {
console.log("WebSocket connection opened");
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());
};
webSocket.onerror = (error) => {
console.error("WebSocket error:", error);
};
webSocket.onclose = (event) => {
console.log("WebSocket connection closed:", event);
};
return () => {
webSocket.close();
};
}, [monacoRef]);
const handleEditorMount = async (
editor: editor.IStandaloneCodeEditor,
monaco: Monaco
@ -80,6 +155,8 @@ export function CodeEditor() {
});
shikiToMonaco(highlighter, monacoRef.current);
await initServices({});
};
return (