2025-02-19 14:46:30 +00:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
import { useEffect } from "react";
|
|
|
|
import dynamic from "next/dynamic";
|
2025-02-19 16:30:45 +00:00
|
|
|
import { useTheme } from "next-themes";
|
2025-02-19 14:46:30 +00:00
|
|
|
import normalizeUrl from "normalize-url";
|
2025-02-19 16:30:45 +00:00
|
|
|
import { highlighter } from "@/lib/shiki";
|
|
|
|
import { shikiToMonaco } from "@shikijs/monaco";
|
2025-02-19 14:46:30 +00:00
|
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
2025-02-20 06:06:13 +00:00
|
|
|
import { useCodeEditorState } from "@/store/useCodeEditor";
|
2025-02-20 01:11:31 +00:00
|
|
|
import { CODE_EDITOR_OPTIONS } from "@/constants/code-editor-options";
|
2025-02-19 16:30:45 +00:00
|
|
|
import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from "vscode-ws-jsonrpc";
|
2025-02-19 14:46:30 +00:00
|
|
|
|
|
|
|
const DynamicEditor = dynamic(
|
|
|
|
async () => {
|
2025-02-19 16:30:45 +00:00
|
|
|
await import("vscode");
|
2025-02-19 14:46:30 +00:00
|
|
|
|
|
|
|
const monaco = await import("monaco-editor");
|
|
|
|
const { loader, Editor } = await import("@monaco-editor/react");
|
|
|
|
|
|
|
|
loader.config({ monaco });
|
|
|
|
|
|
|
|
return Editor;
|
|
|
|
},
|
|
|
|
{ ssr: false }
|
|
|
|
);
|
|
|
|
|
|
|
|
export default function CodeEditor() {
|
2025-02-19 16:30:45 +00:00
|
|
|
const { resolvedTheme } = useTheme();
|
2025-02-20 06:06:13 +00:00
|
|
|
const { language } = useCodeEditorState();
|
2025-02-19 16:30:45 +00:00
|
|
|
|
2025-02-19 14:46:30 +00:00
|
|
|
useEffect(() => {
|
2025-02-20 00:44:11 +00:00
|
|
|
const lspUrl = process.env.NEXT_PUBLIC_LSP_C_URL || "ws://localhost:4594/clangd";
|
|
|
|
const url = normalizeUrl(lspUrl);
|
2025-02-19 14:46:30 +00:00
|
|
|
const webSocket = new WebSocket(url);
|
|
|
|
|
|
|
|
webSocket.onopen = async () => {
|
|
|
|
const socket = toSocket(webSocket);
|
|
|
|
const reader = new WebSocketMessageReader(socket);
|
|
|
|
const writer = new WebSocketMessageWriter(socket);
|
|
|
|
|
|
|
|
const { MonacoLanguageClient } = await import("monaco-languageclient");
|
2025-02-19 16:30:45 +00:00
|
|
|
const { ErrorAction, CloseAction } = await import("vscode-languageclient");
|
2025-02-19 14:46:30 +00:00
|
|
|
|
|
|
|
const languageClient = new MonacoLanguageClient({
|
|
|
|
name: "C Language Client",
|
|
|
|
clientOptions: {
|
|
|
|
documentSelector: ["c"],
|
|
|
|
errorHandler: {
|
|
|
|
error: () => ({ action: ErrorAction.Continue }),
|
|
|
|
closed: () => ({ action: CloseAction.DoNotRestart }),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
connectionProvider: {
|
|
|
|
get: () => Promise.resolve({ reader, writer }),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
languageClient.start();
|
|
|
|
reader.onClose(() => languageClient.stop());
|
|
|
|
};
|
|
|
|
|
|
|
|
webSocket.onerror = (event) => {
|
|
|
|
console.error("WebSocket error observed:", event);
|
|
|
|
};
|
|
|
|
|
|
|
|
webSocket.onclose = (event) => {
|
|
|
|
console.log("WebSocket closed:", event);
|
|
|
|
};
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
webSocket.close();
|
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
return (
|
2025-02-19 16:59:53 +00:00
|
|
|
<DynamicEditor
|
2025-02-20 06:06:13 +00:00
|
|
|
defaultLanguage={language}
|
2025-02-19 16:59:53 +00:00
|
|
|
defaultValue="# include<stdio.h>"
|
|
|
|
path="file:///main.c"
|
2025-02-20 06:06:13 +00:00
|
|
|
theme={resolvedTheme === "light" ? "github-light-default" : "github-dark-default"}
|
2025-02-19 16:59:53 +00:00
|
|
|
height="100%"
|
2025-02-20 01:11:31 +00:00
|
|
|
options={CODE_EDITOR_OPTIONS}
|
2025-02-19 16:59:53 +00:00
|
|
|
beforeMount={(monaco) => {
|
|
|
|
shikiToMonaco(highlighter, monaco);
|
|
|
|
}}
|
2025-02-20 01:17:31 +00:00
|
|
|
// onValidate={(markers) => {
|
|
|
|
// markers.forEach((marker) =>
|
|
|
|
// console.log("onValidate:", marker.message)
|
|
|
|
// );
|
|
|
|
// }}
|
2025-02-19 17:05:30 +00:00
|
|
|
loading={<Skeleton className="h-full w-full" />}
|
2025-02-19 16:59:53 +00:00
|
|
|
/>
|
2025-02-19 14:46:30 +00:00
|
|
|
);
|
|
|
|
}
|