From 2d3403bb84428d47a26ba7d0f0cf5972ff7677d7 Mon Sep 17 00:00:00 2001 From: IRBorisov <8611739+IRBorisov@users.noreply.github.com> Date: Tue, 20 Feb 2024 13:12:06 +0300 Subject: [PATCH] Minor UI improvements --- .../src/components/Help/HelpConstituenta.tsx | 10 +++--- .../src/components/RSInput/RSInput.tsx | 21 ++++++++++-- rsconcept/frontend/src/models/rsformAPI.ts | 32 +++++++++++++++++-- .../RSFormPage/EditorRSForm/FormRSForm.tsx | 2 +- 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/rsconcept/frontend/src/components/Help/HelpConstituenta.tsx b/rsconcept/frontend/src/components/Help/HelpConstituenta.tsx index 44ee348a..cf4a2177 100644 --- a/rsconcept/frontend/src/components/Help/HelpConstituenta.tsx +++ b/rsconcept/frontend/src/components/Help/HelpConstituenta.tsx @@ -7,17 +7,19 @@ function HelpConstituenta() {

Редактор конституент

Сохранить изменения: Ctrl + S или клик по кнопке Сохранить

-

Формальное определение: обратите внимание на кнопки снизу
Горячие клавиши указаны в подсказках при наведении

-

Поля Термин и Определение: Ctrl + Пробел открывает диалог редактирования отсылок
Перед открытием диалога переместите текстовый курсор на заменяемое слово или ссылку

+

Формальное определение

+

- Ctrl + Пробел после ввода первой буквы дополняет до незанятого имени

+

- специальные конструкции вводятся с помощью кнопок снизу

+

Термин и Определение: Ctrl + Пробел открывает диалог редактирования отсылок
Перед открытием диалога переместите текстовый курсор на заменяемое слово или ссылку

Список конституент справа: обратите внимание на настройки фильтрации

- первая настройка - атрибуты конституенты

- вторая настройка - принцип отбора конституент по графу термов

-

- текущая конституента выделена цветом строки

+

- текущая конституента выделена цветом

- двойной клик / Alt + клик - выбор редактируемой конституенты

- при наведении на имя конституенты отображаются ее атрибуты

- столбец "Описание" содержит один из непустых текстовых атрибутов

- +
); diff --git a/rsconcept/frontend/src/components/RSInput/RSInput.tsx b/rsconcept/frontend/src/components/RSInput/RSInput.tsx index d1a78753..4ab468bb 100644 --- a/rsconcept/frontend/src/components/RSInput/RSInput.tsx +++ b/rsconcept/frontend/src/components/RSInput/RSInput.tsx @@ -11,6 +11,8 @@ import { forwardRef, useCallback, useMemo, useRef } from 'react'; import Label from '@/components/ui/Label'; import { useRSForm } from '@/context/RSFormContext'; import { useConceptTheme } from '@/context/ThemeContext'; +import { generateAlias, getCstTypePrefix, guessCstType } from '@/models/rsformAPI'; +import { extractGlobals } from '@/models/rslangAPI'; import { ccBracketMatching } from './bracketMatching'; import { RSLanguage } from './rslang'; @@ -106,7 +108,22 @@ const RSInput = forwardRef( return; } const text = new RSTextWrapper(thisRef.current as Required); - if (event.altKey) { + if (event.ctrlKey && event.code === 'Space') { + const selection = text.getSelection(); + if (!selection.empty || !schema) { + return; + } + const hint = text.getText(selection.from - 1, selection.from); + const type = guessCstType(hint); + if (hint === getCstTypePrefix(type)) { + text.setSelection(selection.from - 1, selection.from); + } + const takenAliases = [...extractGlobals(thisRef.current.view?.state.doc.toString() ?? '')]; + const newAlias = generateAlias(type, schema, takenAliases); + text.replaceWith(newAlias); + event.preventDefault(); + event.stopPropagation(); + } else if (event.altKey) { if (text.processAltKey(event.code, event.shiftKey)) { event.preventDefault(); event.stopPropagation(); @@ -124,7 +141,7 @@ const RSInput = forwardRef( event.stopPropagation(); } }, - [thisRef, onAnalyze] + [thisRef, onAnalyze, schema] ); return ( diff --git a/rsconcept/frontend/src/models/rsformAPI.ts b/rsconcept/frontend/src/models/rsformAPI.ts index 2ebd5a80..98931983 100644 --- a/rsconcept/frontend/src/models/rsformAPI.ts +++ b/rsconcept/frontend/src/models/rsformAPI.ts @@ -244,6 +244,27 @@ export function getCstTypePrefix(type: CstType) { } } +/** + * Guess {@link CstType} from user input hint. + */ +export function guessCstType(hint: string, defaultType: CstType = CstType.TERM) { + if (hint.length !== 1) { + return defaultType; + } + // prettier-ignore + switch (hint) { + case 'X': return CstType.BASE; + case 'C': return CstType.CONSTANT; + case 'S': return CstType.STRUCTURED; + case 'A': return CstType.AXIOM; + case 'D': return CstType.TERM; + case 'F': return CstType.FUNCTION; + case 'P': return CstType.PREDICATE; + case 'T': return CstType.THEOREM; + } + return defaultType; +} + /** * Validate new alias against {@link CstType} and {@link IRSForm}. */ @@ -261,17 +282,22 @@ export function getDefinitionPrefix(cst: IConstituenta): string { /** * Generate alias for new {@link IConstituenta} of a given {@link CstType} for current {@link IRSForm}. */ -export function generateAlias(type: CstType, schema: IRSForm): string { +export function generateAlias(type: CstType, schema: IRSForm, takenAliases: string[] = []): string { const prefix = getCstTypePrefix(type); if (!schema.items || schema.items.length <= 0) { return `${prefix}1`; } - const index = schema.items.reduce((prev, cst, index) => { + let index = schema.items.reduce((prev, cst, index) => { if (cst.cst_type !== type) { return prev; } index = Number(cst.alias.slice(1 - cst.alias.length)) + 1; return Math.max(prev, index); }, 1); - return `${prefix}${index}`; + let alias = `${prefix}${index}`; + while (takenAliases.includes(alias)) { + index = index + 1; + alias = `${prefix}${index}`; + } + return alias; } diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm/FormRSForm.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm/FormRSForm.tsx index 0f3928e0..3f5b2f8d 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm/FormRSForm.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm/FormRSForm.tsx @@ -88,7 +88,7 @@ function FormRSForm({ id, disabled, isModified, setIsModified }: FormRSFormProps return (