import { ReactCodeMirrorRef } from '@uiw/react-codemirror'; import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react'; import Button from '../../components/Common/Button'; import { Loader } from '../../components/Common/Loader'; import RSInput from '../../components/RSInput'; import { 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({ activeCst, disabled, isActive, value, onShowAST, toggleEditMode, setTypification, onChange, ... props }: 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 EditButtons = useMemo(() => { return (
); }, [handleEdit]); return (
{isActive && !disabled && EditButtons}
{ (isActive || loading || parseData) &&
{ loading && } { !loading && parseData && onShowAST(value, ast)} onShowError={onShowError} />}
}
); } export default EditorRSExpression;