import { ReactCodeMirrorRef } from '@uiw/react-codemirror'; import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react'; import Button from '../../components/Common/Button'; import Label from '../../components/Common/Label'; import { Loader } from '../../components/Common/Loader'; import RSInput from '../../components/RSInput/RSInput'; import { getSymbolSubstitute, TextWrapper } from '../../components/RSInput/textEditing'; import { useRSForm } from '../../context/RSFormContext'; import useCheckExpression from '../../hooks/useCheckExpression'; import { TokenID } from '../../utils/enums'; import { IConstituenta, IRSErrorDescription, SyntaxTree } from '../../utils/models'; import { getCstExpressionPrefix, getTypificationLabel } from '../../utils/staticUI'; import ParsingResult from './elements/ParsingResult'; import RSLocalButton from './elements/RSLocalButton'; import RSTokenButton from './elements/RSTokenButton'; import StatusBar from './elements/StatusBar'; interface EditorRSExpressionProps { id: string activeCst?: IConstituenta label: string isActive: boolean disabled?: boolean placeholder?: string onShowAST: (expression: string, ast: SyntaxTree) => void toggleEditMode: () => void setTypification: (typificaiton: string) => void value: string onChange: (newValue: string) => void setValue: (expression: string) => void } function EditorRSExpression({ id, activeCst, label, disabled, isActive, placeholder, value, onShowAST, toggleEditMode, setTypification, onChange }: EditorRSExpressionProps) { const { schema } = useRSForm(); const [isModified, setIsModified] = useState(false); const { parseData, checkExpression, resetParse, loading } = useCheckExpression({ schema }); const rsInput = useRef(null); useLayoutEffect(() => { setIsModified(false); resetParse(); }, [activeCst, resetParse]); function handleFocusIn() { toggleEditMode() } function handleChange(newvalue: string) { onChange(newvalue); setIsModified(true); } function handleCheckExpression() { if (!activeCst) { return; } const prefix = getCstExpressionPrefix(activeCst); const expression = prefix + value; checkExpression(expression, parse => { if (parse.errors.length > 0) { onShowError(parse.errors[0]); } else { rsInput.current?.view?.focus(); } setIsModified(false); setTypification(getTypificationLabel({ isValid: parse.parseResult, resultType: parse.typification, args: parse.args })); }); } const onShowError = useCallback( (error: IRSErrorDescription) => { if (!activeCst || !rsInput.current) { return; } const prefix = getCstExpressionPrefix(activeCst); const errorPosition = error.position - prefix.length; rsInput.current?.view?.dispatch({ selection: { anchor: errorPosition, head: errorPosition } }); rsInput.current?.view?.focus(); }, [activeCst]); const handleEdit = useCallback((id: TokenID, key?: string) => { if (!rsInput.current || !rsInput.current.editor || !rsInput.current.state || !rsInput.current.view) { return; } const text = new TextWrapper(rsInput.current as Required); if (id === TokenID.ID_LOCAL) { text.insertChar(key ?? 'unknown_local'); } else { text.insertToken(id); } rsInput.current?.view?.focus(); setIsModified(true); }, []); const handleInput = useCallback( (event: React.KeyboardEvent) => { if (!rsInput.current) { return; } const text = new TextWrapper(rsInput.current as Required); if (event.shiftKey && event.key === '*' && !event.altKey) { text.insertToken(TokenID.DECART); } else if (event.altKey) { if (!text.processAltKey(event.key)) { return; } } else if (!event.ctrlKey) { const newSymbol = getSymbolSubstitute(event.key); if (!newSymbol) { return; } text.replaceWith(newSymbol); } else { return; } event.preventDefault(); setIsModified(true); }, []); const EditButtons = useMemo(() => { return (
); }, [handleEdit]); return (
); } export default EditorRSExpression;