Skip to content

Commit

Permalink
feat(code-editor): use monaco editor
Browse files Browse the repository at this point in the history
  • Loading branch information
Nirlep5252 committed Dec 24, 2024
1 parent 839e2f2 commit ee973d9
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 127 deletions.
2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@codemirror/lang-python": "^6.1.4",
"@codemirror/language": "^6.10.1",
"@heroicons/react": "^2.1.1",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
Expand All @@ -47,6 +48,7 @@
"html-react-parser": "^5.1.7",
"katex": "^0.16.9",
"lucide-react": "^0.312.0",
"monaco-editor": "^0.52.2",
"next-themes": "^0.3.0",
"react": "^18.2.0",
"react-confetti": "^6.1.0",
Expand Down
26 changes: 13 additions & 13 deletions frontend/src/components/code-editor/code-editor-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import {
SelectTrigger,
} from "@/components/ui/select";
import { useCodeEditorSettings } from "@/stores/code-editor-settings-store";
import * as themes from "@uiw/codemirror-themes-all";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { useDynamicDashboardLayout } from "@/stores/dynamic-dashboard";

const allThemes = Object.keys(themes).filter(
(val) => !val.startsWith("defaultSettings") && !val.endsWith("Init")
) as unknown as (keyof typeof themes)[];
const editorThemes = [
{ label: "Light", value: "light" },
{ label: "Dark", value: "dark" },
{ label: "High Contrast", value: "hc-black" },
{ label: "High Contrast Light", value: "hc-light" },
] as const;

interface Props {}

Expand All @@ -26,18 +28,16 @@ export const CodeEditorSettings: React.FC<Props> = () => {
<div className="flex flex-col gap-4">
<Label className="flex flex-col gap-2">
<div className="ml-1">Editor Theme</div>
<Select
onValueChange={(value) =>
setTheme(value as (typeof allThemes)[number])
}
>
<SelectTrigger>{theme}</SelectTrigger>
<Select onValueChange={(value: typeof theme) => setTheme(value)}>
<SelectTrigger>
{editorThemes.find((t) => t.value === theme)?.label || theme}
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Select Theme</SelectLabel>
{allThemes.map((theme) => (
<SelectItem value={theme} key={theme}>
{theme}
{editorThemes.map((theme) => (
<SelectItem value={theme.value} key={theme.value}>
{theme.label}
</SelectItem>
))}
</SelectGroup>
Expand Down
172 changes: 80 additions & 92 deletions frontend/src/components/code-editor/code-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { useState } from "react";

import { Button } from "@/components/ui/button";

import CodeMirror from "@uiw/react-codemirror";
import * as themes from "@uiw/codemirror-themes-all";
import { loadLanguage, langs } from "@uiw/codemirror-extensions-langs";
import Editor from "@monaco-editor/react";
import { Loader2Icon, SettingsIcon } from "lucide-react";
import { useSourceCodeStore } from "@/stores/source-code";
import { useCodeEditorSettings } from "@/stores/code-editor-settings-store";
Expand All @@ -25,74 +21,44 @@ import {
} from "@/components/ui/select";
import { judge0Languages } from "@/lib/judge0/languages";

loadLanguage("c");
loadLanguage("cpp");
loadLanguage("clojure");
loadLanguage("csharp");
loadLanguage("cobol");
loadLanguage("commonLisp");
loadLanguage("d");
loadLanguage("erlang");
loadLanguage("fortran");
loadLanguage("go");
loadLanguage("groovy");
loadLanguage("haskell");
loadLanguage("java");
loadLanguage("javascript");
loadLanguage("kotlin");
loadLanguage("lua");
loadLanguage("objectiveC");
loadLanguage("octave");
loadLanguage("pascal");
loadLanguage("perl");
loadLanguage("php");
loadLanguage("python");
loadLanguage("r");
loadLanguage("ruby");
loadLanguage("rust");
loadLanguage("scala");
loadLanguage("sql");
loadLanguage("swift");
loadLanguage("typescript");

// http://localhost:2358/languages
const supportedLanguages = {
75: langs.c(),
76: langs.cpp(),
48: langs.c(),
52: langs.cpp(),
49: langs.c(),
53: langs.cpp(),
50: langs.c(),
54: langs.cpp(),
86: langs.clojure(),
51: langs.csharp(),
77: langs.cobol(),
55: langs.commonLisp(),
56: langs.d(),
58: langs.erlang(),
59: langs.fortran(),
60: langs.go(),
88: langs.groovy(),
61: langs.haskell(),
62: langs.java(),
63: langs.javascript(),
78: langs.kotlin(),
64: langs.lua(),
79: langs.objectiveC(),
66: langs.octave(),
67: langs.pascal(),
85: langs.perl(),
68: langs.php(),
70: langs.python(),
71: langs.python(),
80: langs.r(),
72: langs.ruby(),
73: langs.rust(),
81: langs.scala(),
82: langs.sql(),
83: langs.swift(),
74: langs.typescript(),
// Monaco language mapping for Judge0 language IDs
const languageMap: { [key: number]: string } = {
75: "c",
76: "cpp",
48: "c",
52: "cpp",
49: "c",
53: "cpp",
50: "c",
54: "cpp",
86: "clojure",
51: "csharp",
77: "cobol",
55: "lisp",
56: "d",
58: "erlang",
59: "fortran",
60: "go",
88: "groovy",
61: "haskell",
62: "java",
63: "javascript",
78: "kotlin",
64: "lua",
79: "objective-c",
66: "matlab",
67: "pascal",
85: "perl",
68: "php",
70: "python",
71: "python",
80: "r",
72: "ruby",
73: "rust",
81: "scala",
82: "sql",
83: "swift",
74: "typescript",
};

interface Props {
Expand All @@ -108,6 +74,7 @@ export const CodeEditor: React.FC<Props> = (props) => {
const { sourceCodeMap, setSourceCode } = useSourceCodeStore();
const sourceCode = sourceCodeMap?.[props.codeId] || "";

const [currentCode, setCurrentCode] = useState<string>(sourceCode);
const [isRunning, setIsRunning] = useState<boolean>(false);
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);

Expand Down Expand Up @@ -148,7 +115,7 @@ export const CodeEditor: React.FC<Props> = (props) => {
variant="outline"
onClick={async () => {
setIsRunning(true);
await props.onRun(sourceCode, parseInt(language));
await props.onRun(currentCode, parseInt(language));
setIsRunning(false);
}}
>
Expand All @@ -159,34 +126,55 @@ export const CodeEditor: React.FC<Props> = (props) => {
variant="default"
onClick={async () => {
setIsSubmitting(true);
await props.onSubmit(sourceCode, parseInt(language));
await props.onSubmit(currentCode, parseInt(language));
setIsSubmitting(false);
}}
>
{isSubmitting ? <Loader2Icon className="animate-spin" /> : "Submit"}
</Button>
</div>

<CodeMirror
<Editor
value={sourceCode}
onChange={(newValue) => setSourceCode(props.codeId, newValue)}
// @ts-expect-error stfu bitch i know what i am doing
theme={themes[theme]}
// @ts-expect-error - this is stupid but it works, fuck you typescript
extensions={[supportedLanguages[parseInt(language)]]}
basicSetup={{
autocompletion: true,
foldGutter: true,
tabSize: 4,
onChange={(value) => {
setCurrentCode(value || "");
setSourceCode(props.codeId, value || "");
}}
style={{
width: "100%",
height: "100%",
overflow: "scroll",
fontSize: "20px",
theme={theme === "dark" ? "vs-dark" : "light"}
language={languageMap[parseInt(language)] || "plaintext"}
options={{
minimap: { enabled: false },
fontSize: 20,
automaticLayout: true,
tabSize: 4,
scrollBeyondLastLine: false,
quickSuggestions: {
other: true,
comments: true,
strings: true,
},
suggestOnTriggerCharacters: true,
acceptSuggestionOnEnter: "on",
tabCompletion: "on",
wordBasedSuggestions: "currentDocument",
parameterHints: { enabled: true },
suggest: {
showKeywords: true,
showSnippets: true,
showClasses: true,
showFunctions: true,
showVariables: true,
showModules: true,
showIcons: true,
showFiles: true,
},
snippetSuggestions: "top",
hover: { enabled: true },
formatOnPaste: true,
formatOnType: true,
}}
placeholder={"Please enter the code."}
minHeight="100%"
height="100%"
width="100%"
/>
</div>
);
Expand Down
33 changes: 11 additions & 22 deletions frontend/src/stores/code-editor-settings-store.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,17 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";

interface State {
theme: string;
language: string;
}
type MonacoTheme = "light" | "dark" | "hc-black" | "hc-light";

interface Actions {
setTheme: (theme: string) => void;
interface CodeEditorSettingsStore {
language: string;
setLanguage: (language: string) => void;
theme: MonacoTheme;
setTheme: (theme: MonacoTheme) => void;
}

export const useCodeEditorSettings = create<State & Actions>()(
persist(
(set) => {
return {
theme: "tokyoNight",
language: "71",
setTheme: (theme) => set({ theme }),
setLanguage: (language) => set({ language }),
};
},
{
name: "code-editor-settings",
}
)
);
export const useCodeEditorSettings = create<CodeEditorSettingsStore>((set) => ({
language: "71",
setLanguage: (language) => set({ language }),
theme: "dark",
setTheme: (theme) => set({ theme }),
}));

0 comments on commit ee973d9

Please sign in to comment.