// Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 import { MonacoCodeEditor } from "@/app/monaco/monaco-react"; import { useOverrideConfigAtom } from "@/app/store/global"; import { boundNumber } from "@/util/util"; import type * as MonacoTypes from "monaco-editor"; import * as MonacoModule from "monaco-editor"; import React, { useMemo, useRef } from "react"; function defaultEditorOptions(): MonacoTypes.editor.IEditorOptions { const opts: MonacoTypes.editor.IEditorOptions = { scrollBeyondLastLine: false, fontSize: 12, fontFamily: "Hack", smoothScrolling: true, scrollbar: { useShadows: false, verticalScrollbarSize: 5, horizontalScrollbarSize: 5, }, minimap: { enabled: true, }, stickyScroll: { enabled: false, }, }; return opts; } interface CodeEditorProps { blockId: string; text: string; readonly: boolean; language?: string; fileName?: string; onChange?: (text: string) => void; onMount?: (monacoPtr: MonacoTypes.editor.IStandaloneCodeEditor, monaco: typeof MonacoModule) => () => void; } export function CodeEditor({ blockId, text, language, fileName, readonly, onChange, onMount }: CodeEditorProps) { const divRef = useRef(null); const unmountRef = useRef<() => void>(null); const minimapEnabled = useOverrideConfigAtom(blockId, "editor:minimapenabled") ?? false; const stickyScrollEnabled = useOverrideConfigAtom(blockId, "editor:stickyscrollenabled") ?? false; const wordWrap = useOverrideConfigAtom(blockId, "editor:wordwrap") ?? false; const fontSize = boundNumber(useOverrideConfigAtom(blockId, "editor:fontsize"), 6, 64); const uuidRef = useRef(crypto.randomUUID()).current; let editorPath: string; if (fileName) { const separator = fileName.startsWith("/") ? "" : "/"; editorPath = blockId + separator + fileName; } else { editorPath = uuidRef; } React.useEffect(() => { return () => { // unmount function if (unmountRef.current) { unmountRef.current(); } }; }, []); function handleEditorChange(text: string) { if (onChange) { onChange(text); } } function handleEditorOnMount( editor: MonacoTypes.editor.IStandaloneCodeEditor, monaco: typeof MonacoModule ): () => void { if (onMount) { const cleanup = onMount(editor, monaco); unmountRef.current = cleanup; return cleanup; } return undefined; } const editorOpts = useMemo(() => { const opts = defaultEditorOptions(); opts.minimap.enabled = minimapEnabled; opts.stickyScroll.enabled = stickyScrollEnabled; opts.wordWrap = wordWrap ? "on" : "off"; opts.fontSize = fontSize; opts.copyWithSyntaxHighlighting = false; return opts; }, [minimapEnabled, stickyScrollEnabled, wordWrap, fontSize, readonly]); return (
); }