feat: using codeium editor instead of codemirror

This commit is contained in:
2024-03-06 00:04:55 +07:00
parent 6919e7126b
commit 3f1603722f
6 changed files with 262 additions and 520 deletions
+117 -86
View File
@@ -1,27 +1,17 @@
/* eslint-disable react/display-name */
import ReactCodeMirror, {
EditorView,
ReactCodeMirrorRef,
keymap,
} from "@uiw/react-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { css } from "@codemirror/lang-css";
import { html } from "@codemirror/lang-html";
import { json } from "@codemirror/lang-json";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { tokyoNight } from "@uiw/codemirror-theme-tokyo-night";
import { vscodeKeymap } from "@replit/codemirror-vscode-keymap";
import { CodeiumEditor } from "@codeium/react-code-editor/dist/esm";
import prettier from "prettier/standalone";
import prettierHtmlPlugin from "prettier/plugins/html";
import prettierCssPlugin from "prettier/plugins/postcss";
import prettierBabelPlugin from "prettier/plugins/babel";
import * as prettierPluginEstree from "prettier/plugins/estree";
import { abbreviationTracker } from "@emmetio/codemirror6-plugin";
import { useDebounce } from "~/hooks/useDebounce";
import useCommandKey from "~/hooks/useCommandKey";
import { getFileExt } from "~/lib/utils";
type Props = {
lang?: string;
filename?: string;
path?: string;
value: string;
wordWrap?: boolean;
onChange: (val: string) => void;
@@ -29,114 +19,155 @@ type Props = {
};
const CodeEditor = (props: Props) => {
const codeMirror = useRef<ReactCodeMirrorRef>(null);
const { lang, value, formatOnSave, wordWrap, onChange } = props;
const { filename, path, value, formatOnSave, wordWrap, onChange } = props;
const editorRef = useRef<any>(null);
const [data, setData] = useState(value);
const [debounceChange, resetDebounceChange] = useDebounce(onChange, 3000);
const langMetadata = useMemo(() => getLangMetadata(lang || "plain"), [lang]);
const language = useMemo(() => getLanguage(filename), [filename]);
const onSave = useCallback(async () => {
const editor = editorRef.current;
if (!editor) {
return;
}
const model = editor.getModel();
const content = model.getValue();
const formatter = language.formatter;
if (!formatOnSave || !formatter) {
return onChange(content);
}
try {
const cm = codeMirror.current?.view;
const content = cm ? cm.state.doc.toString() : data;
const formatter = langMetadata.formatter;
const [parser, ...plugins] = formatter;
if (formatOnSave && cm && formatter != null) {
const [parser, ...plugins] = formatter;
const cursor = cm.state.selection.main.head || 0;
const { formatted, cursorOffset } = await prettier.formatWithCursor(
content,
{
parser,
plugins,
cursorOffset: cursor,
printWidth: 64,
}
);
setData(formatted);
onChange(formatted);
if (cm) {
cm.dispatch({
changes: { from: 0, to: cm?.state.doc.length, insert: formatted },
});
cm.dispatch({
selection: { anchor: cursorOffset },
});
const cursor = model.getOffsetAt(editor.getPosition());
const { formatted, cursorOffset } = await prettier.formatWithCursor(
content,
{
parser,
plugins,
cursorOffset: cursor || 0,
printWidth: 64,
}
} else {
onChange(content);
}
);
model.setValue(formatted);
const newCursor = model.getPositionAt(cursorOffset);
editor.setPosition(newCursor);
console.log("huhu set cursor");
onChange(formatted);
} catch (err) {
console.log("prettier error", err);
onChange(content);
}
setTimeout(() => resetDebounceChange(), 100);
}, [
data,
langMetadata.formatter,
formatOnSave,
onChange,
resetDebounceChange,
]);
useCommandKey("s", onSave);
}, [language.formatter, formatOnSave, onChange, resetDebounceChange]);
useEffect(() => {
setData(value);
}, [value]);
const extensions = [...langMetadata.extensions, keymap.of(vscodeKeymap)];
if (wordWrap) {
extensions.push(EditorView.lineWrapping);
}
useCommandKey("s", onSave);
return (
<ReactCodeMirror
ref={codeMirror}
extensions={extensions}
indentWithTab={false}
basicSetup={{ defaultKeymap: false }}
value={data}
onChange={(val) => {
setData(val);
debounceChange(val);
}}
height="100%"
theme={tokyoNight}
/>
<div className="w-full h-full code-editor">
<CodeiumEditor
language={language.name}
theme="vs-dark"
path={path || filename}
value={data}
height="100%"
onMount={(editor: any, _monaco: any) => {
editorRef.current = editor;
}}
onChange={(e: string) => debounceChange(e)}
/>
</div>
);
};
function getLangMetadata(lang: string) {
let extensions: any[] = [];
// generate this as enum of languages
enum Languages {
Abap = "abap",
Apex = "apex",
Azcli = "azcli",
Bat = "bat",
C = "c",
Clojure = "clojure",
Coffeescript = "coffeescript",
Cpp = "cpp",
Csharp = "csharp",
Csp = "csp",
Css = "css",
Dockerfile = "dockerfile",
Fsharp = "fsharp",
Go = "go",
Graphql = "graphql",
Handlebars = "handlebars",
Html = "html",
Ini = "ini",
Java = "java",
Javascript = "javascript",
Json = "json",
Less = "less",
Lua = "lua",
Markdown = "markdown",
M3 = "m3",
Msdax = "msdax",
Mysql = "mysql",
Objective = "objective",
Pgsql = "pgsql",
Php = "php",
Postiats = "postiats",
Powershell = "powershell",
Pug = "pug",
Python = "python",
R = "r",
Razor = "razor",
Redis = "redis",
Redshift = "redshift",
Ruby = "ruby",
Sb = "sb",
Scss = "scss",
Shell = "shell",
Solidity = "solidity",
Sql = "sql",
Swift = "swift",
Typescript = "typescript",
Vb = "vb",
Xml = "xml",
Yaml = "yaml",
Common = "common",
}
function getLanguage(filename?: string | null) {
const ext = getFileExt(filename || "");
let name: Languages = Languages.Common;
let formatter: any = null;
switch (lang) {
switch (ext) {
case "html":
extensions = [html({ selfClosingTags: true }), abbreviationTracker()];
name = Languages.Html;
formatter = ["html", prettierHtmlPlugin];
break;
case "css":
extensions = [css()];
name = Languages.Css;
formatter = ["css", prettierCssPlugin];
break;
case "json":
extensions = [json()];
name = Languages.Json;
formatter = ["json", prettierBabelPlugin, prettierPluginEstree];
break;
case "jsx":
case "js":
case "ts":
case "tsx":
const isTypescript = ["tsx", "ts"].includes(lang);
extensions = [
javascript({
jsx: ["jsx", "tsx"].includes(lang),
typescript: isTypescript,
}),
];
const isTypescript = ["tsx", "ts"].includes(ext);
name = isTypescript ? Languages.Typescript : Languages.Javascript;
formatter = [
isTypescript ? "babel-ts" : "babel",
prettierBabelPlugin,
@@ -145,7 +176,7 @@ function getLangMetadata(lang: string) {
break;
}
return { extensions, formatter };
return { name, formatter };
}
export default CodeEditor;