Finalize templated constituents UI

This commit is contained in:
IRBorisov 2023-11-06 18:44:14 +03:00
parent cc79fffd34
commit 643f43c819
4 changed files with 73 additions and 36 deletions

View File

@ -50,12 +50,13 @@ extends Pick<ReactCodeMirrorProps,
label?: string label?: string
dimensions?: string dimensions?: string
disabled?: boolean disabled?: boolean
noTooltip?: boolean
innerref?: RefObject<ReactCodeMirrorRef> | undefined innerref?: RefObject<ReactCodeMirrorRef> | undefined
onChange?: (newValue: string) => void onChange?: (newValue: string) => void
} }
function RSInput({ function RSInput({
id, label, innerref, onChange, disabled, id, label, innerref, onChange, disabled, noTooltip,
dimensions = 'w-full', dimensions = 'w-full',
...props ...props
}: RSInputProps) { }: RSInputProps) {
@ -94,8 +95,8 @@ function RSInput({
EditorView.lineWrapping, EditorView.lineWrapping,
RSLanguage, RSLanguage,
ccBracketMatching(darkMode), ccBracketMatching(darkMode),
rsHoverTooltip(schema?.items || []), ... noTooltip ? [] : [rsHoverTooltip(schema?.items || [])],
], [darkMode, schema?.items]); ], [darkMode, schema?.items, noTooltip]);
const handleInput = useCallback( const handleInput = useCallback(
(event: React.KeyboardEvent<HTMLDivElement>) => { (event: React.KeyboardEvent<HTMLDivElement>) => {

View File

@ -132,15 +132,17 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
/> />
</div> </div>
<div <div className='flex items-center justify-center w-full gap-2 select-none'>
title='Выберите аргумент из списка сверху и значение из списка снизу' <span title='Выберите аргумент из списка сверху и значение из списка снизу'
className='flex items-center justify-center w-full gap-2 select-none' className='font-semibold text-center'
> >
<span className='font-semibold text-center'>{selectedArgument?.alias || 'ARG'}</span> {selectedArgument?.alias || 'ARG'}
</span>
<span>=</span> <span>=</span>
<RSInput <RSInput
dimensions='max-w-[12rem] w-full' dimensions='max-w-[12rem] w-full'
value={argumentValue} value={argumentValue}
noTooltip
onChange={newValue => setArgumentValue(newValue)} onChange={newValue => setArgumentValue(newValue)}
/> />
<MiniButton <MiniButton

View File

@ -7,7 +7,7 @@ import Modal, { ModalProps } from '../../components/Common/Modal';
import HelpRSTemplates from '../../components/Help/HelpRSTemplates'; import HelpRSTemplates from '../../components/Help/HelpRSTemplates';
import { HelpIcon } from '../../components/Icons'; import { HelpIcon } from '../../components/Icons';
import usePartialUpdate from '../../hooks/usePartialUpdate'; import usePartialUpdate from '../../hooks/usePartialUpdate';
import { CstType, ICstCreateData, IRSForm } from '../../models/rsform'; import { CstType, ICstCreateData, inferTemplatedType, IRSForm, substituteTemplateArgs } from '../../models/rsform';
import { createAliasFor, validateCstAlias } from '../../utils/misc'; import { createAliasFor, validateCstAlias } from '../../utils/misc';
import ArgumentsTab, { IArgumentsState } from './ArgumentsTab'; import ArgumentsTab, { IArgumentsState } from './ArgumentsTab';
import ConstituentaTab from './ConstituentaTab'; import ConstituentaTab from './ConstituentaTab';
@ -27,12 +27,12 @@ export enum TabID {
function DlgConstituentaTemplate({ hideWindow, schema, onCreate }: DlgConstituentaTemplateProps) { function DlgConstituentaTemplate({ hideWindow, schema, onCreate }: DlgConstituentaTemplateProps) {
const [validated, setValidated] = useState(false); const [validated, setValidated] = useState(false);
const [ templateData, updateTemplateData ] = usePartialUpdate<ITemplateState>({}); const [ template, updateTemplate ] = usePartialUpdate<ITemplateState>({});
const [ argumentsData, updateArgumentsData ] = usePartialUpdate<IArgumentsState>({ const [ substitutes, updateSubstitutes ] = usePartialUpdate<IArgumentsState>({
definition: '', definition: '',
arguments: [] arguments: []
}); });
const [cstData, updateCstData] = usePartialUpdate<ICstCreateData>({ const [constituenta, updateConstituenta] = usePartialUpdate<ICstCreateData>({
cst_type: CstType.TERM, cst_type: CstType.TERM,
insert_after: null, insert_after: null,
alias: '', alias: '',
@ -45,40 +45,40 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate }: DlgConstituen
const [ activeTab, setActiveTab ] = useState(TabID.TEMPLATE); const [ activeTab, setActiveTab ] = useState(TabID.TEMPLATE);
const handleSubmit = () => onCreate(cstData); const handleSubmit = () => onCreate(constituenta);
useLayoutEffect( useLayoutEffect(
() => { () => {
updateCstData({ alias: createAliasFor(cstData.cst_type, schema) }); updateConstituenta({ alias: createAliasFor(constituenta.cst_type, schema) });
}, [cstData.cst_type, updateCstData, schema]); }, [constituenta.cst_type, updateConstituenta, schema]);
useEffect( useEffect(
() => { () => {
setValidated(validateCstAlias(cstData.alias, cstData.cst_type, schema)); setValidated(validateCstAlias(constituenta.alias, constituenta.cst_type, schema));
}, [cstData.alias, cstData.cst_type, schema]); }, [constituenta.alias, constituenta.cst_type, schema]);
useLayoutEffect( useLayoutEffect(
() => { () => {
if (!templateData.prototype) { if (!template.prototype) {
updateCstData({ updateConstituenta({
definition_raw: '', definition_raw: '',
definition_formal: '', definition_formal: '',
term_raw: '' term_raw: ''
}); });
updateArgumentsData({ updateSubstitutes({
definition: '', definition: '',
arguments: [] arguments: []
}); });
} else { } else {
updateCstData({ updateConstituenta({
cst_type: templateData.prototype.cst_type, cst_type: template.prototype.cst_type,
definition_raw: templateData.prototype.definition_raw, definition_raw: template.prototype.definition_raw,
definition_formal: templateData.prototype.definition_formal, definition_formal: template.prototype.definition_formal,
term_raw: templateData.prototype.term_raw term_raw: template.prototype.term_raw
}); });
updateArgumentsData({ updateSubstitutes({
definition: templateData.prototype.definition_formal, definition: template.prototype.definition_formal,
arguments: templateData.prototype.parse.args.map( arguments: template.prototype.parse.args.map(
arg => ({ arg => ({
alias: arg.alias, alias: arg.alias,
typification: arg.typification, typification: arg.typification,
@ -87,7 +87,23 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate }: DlgConstituen
) )
}); });
} }
}, [templateData.prototype, updateCstData, updateArgumentsData]); }, [template.prototype, updateConstituenta, updateSubstitutes]);
useLayoutEffect(
() => {
if (substitutes.arguments.length === 0 || !template.prototype) {
return;
}
const definition = substituteTemplateArgs(template.prototype.definition_formal, substitutes.arguments);
const type = inferTemplatedType(template.prototype.cst_type, substitutes.arguments);
updateConstituenta({
cst_type: type,
definition_formal: definition,
});
updateSubstitutes({
definition: definition,
});
}, [substitutes.arguments, template.prototype, updateConstituenta, updateSubstitutes]);
return ( return (
<Modal <Modal
@ -133,23 +149,23 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate }: DlgConstituen
<div className='w-full'> <div className='w-full'>
<TabPanel> <TabPanel>
<TemplateTab <TemplateTab
state={templateData} state={template}
partialUpdate={updateTemplateData} partialUpdate={updateTemplate}
/> />
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<ArgumentsTab <ArgumentsTab
schema={schema} schema={schema}
state={argumentsData} state={substitutes}
partialUpdate={updateArgumentsData} partialUpdate={updateSubstitutes}
/> />
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<ConstituentaTab <ConstituentaTab
state={cstData} state={constituenta}
partialUpdate={updateCstData} partialUpdate={updateConstituenta}
/> />
</TabPanel> </TabPanel>
</div> </div>

View File

@ -3,7 +3,7 @@ import { TextMatcher } from '../utils/utils'
import { ILibraryUpdateData } from './library' import { ILibraryUpdateData } from './library'
import { ILibraryItem } from './library' import { ILibraryItem } from './library'
import { CstMatchMode } from './miscelanious' import { CstMatchMode } from './miscelanious'
import { IArgumentInfo, ParsingStatus, ValueClass } from './rslang' import { IArgumentInfo, IArgumentValue, ParsingStatus, ValueClass } from './rslang'
export enum CstType { export enum CstType {
BASE = 'basic', BASE = 'basic',
@ -148,6 +148,24 @@ export function extractGlobals(expression: string): Set<string> {
return new Set(expression.match(/[XCSADFPT]\d+/g) ?? []); return new Set(expression.match(/[XCSADFPT]\d+/g) ?? []);
} }
export function inferTemplatedType(templateType: CstType, args: IArgumentValue[]): CstType {
if (args.length === 0 || args.some(arg => !arg.value)) {
return templateType;
} else if (templateType === CstType.PREDICATE) {
return CstType.AXIOM;
} else {
return CstType.TERM;
}
}
export function substituteTemplateArgs(expression: string, args: IArgumentValue[]): string {
if (args.every(arg => !arg.value)) {
return expression;
}
// TODO: figure out actual substitution
return expression;
}
export function loadRSFormData(schema: IRSFormData): IRSForm { export function loadRSFormData(schema: IRSFormData): IRSForm {
const result = schema as IRSForm const result = schema as IRSForm
result.graph = new Graph; result.graph = new Graph;