editor
This commit is contained in:
@@ -2,19 +2,51 @@
|
||||
|
||||
import { useEffect, useRef, forwardRef, useImperativeHandle, useState } from "react";
|
||||
import styles from "@/styles/Editor.module.css";
|
||||
import { loadRhaiWasm, initRhaiMode } from "@/utils/wasmLoader";
|
||||
|
||||
// Dynamic import for CodeMirror to avoid SSR issues
|
||||
let CodeMirror: any = null;
|
||||
let isCodeMirrorReady = false;
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
import("codemirror")
|
||||
.then(async (cm) => {
|
||||
CodeMirror = cm.default;
|
||||
await import("codemirror/mode/javascript/javascript");
|
||||
await import("codemirror/addon/edit/matchbrackets");
|
||||
await import("codemirror/addon/edit/closebrackets");
|
||||
await import("codemirror/addon/selection/active-line");
|
||||
await import("codemirror/lib/codemirror.css");
|
||||
await import("codemirror/theme/monokai.css");
|
||||
await import("codemirror/addon/comment/comment");
|
||||
// @ts-ignore - CodeMirror addon type issues
|
||||
await import("codemirror/addon/fold/brace-fold");
|
||||
// @ts-ignore - CodeMirror addon type issues
|
||||
await import("codemirror/addon/fold/foldgutter");
|
||||
// @ts-ignore - CodeMirror addon type issues
|
||||
await import("codemirror/addon/search/match-highlighter");
|
||||
require("codemirror/lib/codemirror.css");
|
||||
require("codemirror/theme/monokai.css");
|
||||
require("codemirror/addon/fold/foldgutter.css");
|
||||
|
||||
try {
|
||||
await loadRhaiWasm();
|
||||
initRhaiMode(CodeMirror);
|
||||
console.log('✅ WASM-based Rhai mode initialized successfully');
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Failed to load WASM Rhai mode, falling back to JavaScript mode:', error);
|
||||
// Fallback to JavaScript mode if WASM fails
|
||||
CodeMirror.defineMode("rhai", (config: any) => {
|
||||
const jsMode = CodeMirror.getMode(config, "javascript");
|
||||
return {
|
||||
...jsMode,
|
||||
name: "rhai",
|
||||
helperType: "rhai"
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
isCodeMirrorReady = true;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to load CodeMirror:', error);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,7 +58,7 @@ interface EditorProps {
|
||||
}
|
||||
|
||||
export const Editor = forwardRef<any, EditorProps>(function Editor(
|
||||
{ initialValue = "", onChange, onRequestRun, onReady },
|
||||
{ initialValue = "", onChange, onReady },
|
||||
ref,
|
||||
) {
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
@@ -37,19 +69,30 @@ export const Editor = forwardRef<any, EditorProps>(function Editor(
|
||||
|
||||
// Initialize editor only once
|
||||
useEffect(() => {
|
||||
if (!CodeMirror || !textareaRef.current || editorRef.current) return;
|
||||
if (!isCodeMirrorReady || !CodeMirror || !textareaRef.current || editorRef.current) return;
|
||||
|
||||
const editor = CodeMirror.fromTextArea(textareaRef.current, {
|
||||
lineNumbers: true,
|
||||
mode: "javascript", // Placeholder mode, will be 'rhai' when WASM is integrated
|
||||
mode: "rhai",
|
||||
theme: "monokai",
|
||||
indentUnit: 4,
|
||||
matchBrackets: true,
|
||||
autoCloseBrackets: true,
|
||||
foldGutter: {
|
||||
rangeFinder: CodeMirror.fold.brace,
|
||||
},
|
||||
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
|
||||
styleActiveLine: true,
|
||||
extraKeys: {
|
||||
"Ctrl-Enter": () => {
|
||||
onRequestRun?.();
|
||||
},
|
||||
highlightSelectionMatches: {
|
||||
minChars: 3,
|
||||
showToken: true,
|
||||
annotateScrollbar: true,
|
||||
},
|
||||
rulers: [],
|
||||
autoCloseBrackets: {
|
||||
pairs: `()[]{}''""`,
|
||||
closeBefore: `)]}'":;,`,
|
||||
triples: "",
|
||||
explode: "()[]{}",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -70,25 +113,14 @@ export const Editor = forwardRef<any, EditorProps>(function Editor(
|
||||
editorRef.current = null;
|
||||
}
|
||||
};
|
||||
}, []); // Empty dependency array - only initialize once
|
||||
|
||||
// Update keyboard shortcut when onRequestRun changes
|
||||
useEffect(() => {
|
||||
if (editorRef.current && onRequestRun) {
|
||||
editorRef.current.setOption("extraKeys", {
|
||||
"Ctrl-Enter": () => {
|
||||
onRequestRun();
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [onRequestRun]);
|
||||
}, []); // Only run once
|
||||
|
||||
return (
|
||||
<div className={styles.editorContainer}>
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
defaultValue={initialValue}
|
||||
placeholder="Enter your Rhai code here..."
|
||||
placeholder="Code goes here"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -210,7 +210,7 @@ export default function Playground() {
|
||||
className={styles.result}
|
||||
readOnly
|
||||
autoComplete="off"
|
||||
placeholder="Script output will appear here..."
|
||||
placeholder="Use print() to produce output"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -66,7 +66,7 @@ export const Terminal = forwardRef<TerminalRef, {}>(function Terminal(_props, re
|
||||
});
|
||||
|
||||
term.open(terminalRef.current);
|
||||
term.write('Terminal ready...\r\n');
|
||||
term.write('Terminal ready.\r\n');
|
||||
|
||||
xtermRef.current = term;
|
||||
} catch (error) {
|
||||
|
||||
@@ -15,3 +15,24 @@
|
||||
resize: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Enhanced CodeMirror styles from playground */
|
||||
.editorContainer :global(.CodeMirror) {
|
||||
border: 1px solid #ccc;
|
||||
height: 100% !important;
|
||||
box-sizing: border-box;
|
||||
font-size: 0.95em;
|
||||
line-height: initial;
|
||||
}
|
||||
|
||||
.editorContainer :global(.rhai-error) {
|
||||
text-decoration: underline wavy red;
|
||||
}
|
||||
|
||||
.editorContainer :global(.cm-matchhighlight) {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.editorContainer :global(.CodeMirror-selection-highlight-scrollbar) {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
38
webui/src/utils/wasmLoader.ts
Normal file
38
webui/src/utils/wasmLoader.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
// WASM loader for Rhai CodeMirror mode
|
||||
import init, { RhaiMode, init_codemirror_pass } from '@/wasm/rhai-codemirror/rhai_codemirror.js';
|
||||
|
||||
let wasmInitialized = false;
|
||||
let wasmModule: any = null;
|
||||
|
||||
export const loadRhaiWasm = async () => {
|
||||
if (wasmInitialized) {
|
||||
return wasmModule;
|
||||
}
|
||||
|
||||
try {
|
||||
// Initialize the WASM module
|
||||
wasmModule = await init();
|
||||
wasmInitialized = true;
|
||||
|
||||
return wasmModule;
|
||||
} catch (error) {
|
||||
console.error('Failed to load Rhai WASM module:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const initRhaiMode = (CodeMirror: any) => {
|
||||
if (!wasmInitialized || !wasmModule) {
|
||||
throw new Error('WASM module not loaded. Call loadRhaiWasm() first.');
|
||||
}
|
||||
|
||||
// Initialize CodeMirror Pass for the WASM module
|
||||
init_codemirror_pass(CodeMirror.Pass);
|
||||
|
||||
// Define the Rhai mode using the WASM-based RhaiMode
|
||||
CodeMirror.defineMode("rhai", (config: any) => {
|
||||
return new RhaiMode(config.indentUnit || 4);
|
||||
});
|
||||
};
|
||||
|
||||
export { RhaiMode };
|
||||
Reference in New Issue
Block a user