diff --git a/README.md b/README.md index 6d5c9db4..9e089614 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ This readme file is used mostly to document project dependencies - react-tooltip - @uiw/react-codemirror - @uiw/codemirror-themes + - @lezer/lr
@@ -45,6 +46,7 @@ This readme file is used mostly to document project dependencies - jest - ts-jest - @types/jest + - @lezer/generator
diff --git a/rsconcept/frontend/package-lock.json b/rsconcept/frontend/package-lock.json index b22721e1..920083c2 100644 --- a/rsconcept/frontend/package-lock.json +++ b/rsconcept/frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "frontend", "version": "1.0.0", "dependencies": { + "@lezer/lr": "^1.3.9", "@uiw/codemirror-themes": "^4.21.9", "@uiw/react-codemirror": "^4.21.9", "axios": "^1.4.0", @@ -26,6 +27,7 @@ "reagraph": "^4.11.1" }, "devDependencies": { + "@lezer/generator": "^1.4.0", "@types/jest": "^29.5.3", "@types/node": "^20.4.5", "@types/react": "^18.2.15", @@ -3681,6 +3683,19 @@ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.3.tgz", "integrity": "sha512-JH4wAXCgUOcCGNekQPLhVeUtIqjH0yPBs7vvUdSjyQama9618IOKFJwkv2kcqdhF0my8hQEgCTEJU0GIgnahvA==" }, + "node_modules/@lezer/generator": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lezer/generator/-/generator-1.4.0.tgz", + "integrity": "sha512-X/gB7vr7rEhtPQtgGxK61pMFOt60iXUBvANMq7DNO06PxrY6ZAmEEZIfSX8kfaVO/EVd9xARAsvguYDoShcMWA==", + "dev": true, + "dependencies": { + "@lezer/common": "^1.0.2", + "@lezer/lr": "^1.3.0" + }, + "bin": { + "lezer-generator": "dist/lezer-generator.cjs" + } + }, "node_modules/@lezer/highlight": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.6.tgz", diff --git a/rsconcept/frontend/package.json b/rsconcept/frontend/package.json index 72777ced..815bf50f 100644 --- a/rsconcept/frontend/package.json +++ b/rsconcept/frontend/package.json @@ -4,6 +4,7 @@ "version": "1.0.0", "type": "module", "scripts": { + "prepare": "lezer-generator src/components/RSInput/rslang.grammar -o src/components/RSInput/rslangparser.ts", "test": "jest", "dev": "vite", "build": "tsc && vite build", @@ -11,6 +12,7 @@ "preview": "vite preview" }, "dependencies": { + "@lezer/lr": "^1.3.9", "@uiw/codemirror-themes": "^4.21.9", "@uiw/react-codemirror": "^4.21.9", "axios": "^1.4.0", @@ -29,6 +31,7 @@ "reagraph": "^4.11.1" }, "devDependencies": { + "@lezer/generator": "^1.4.0", "@types/jest": "^29.5.3", "@types/node": "^20.4.5", "@types/react": "^18.2.15", diff --git a/rsconcept/frontend/src/components/Common/ConceptDataTable.tsx b/rsconcept/frontend/src/components/Common/ConceptDataTable.tsx index ea619cfe..34906066 100644 --- a/rsconcept/frontend/src/components/Common/ConceptDataTable.tsx +++ b/rsconcept/frontend/src/components/Common/ConceptDataTable.tsx @@ -38,12 +38,21 @@ createTheme('customDark', { } }, 'dark'); +createTheme('customLight', { + divider: { + default: '#d1d5db' + }, + striped: { + default: '#f0f2f7' + }, +}, 'light'); + function ConceptDataTable({ theme, ...props }: TableProps) { const { darkMode } = useConceptTheme(); return ( - theme={ theme ?? (darkMode ? 'customDark' : '')} + theme={ theme ?? (darkMode ? 'customDark' : 'customLight')} {...props} /> ); diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/RSInput.tsx b/rsconcept/frontend/src/components/RSInput/RSInput.tsx similarity index 97% rename from rsconcept/frontend/src/pages/RSFormPage/elements/RSInput.tsx rename to rsconcept/frontend/src/components/RSInput/RSInput.tsx index 254c4fa8..88701847 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/RSInput.tsx +++ b/rsconcept/frontend/src/components/RSInput/RSInput.tsx @@ -5,7 +5,7 @@ import CodeMirror, { BasicSetupOptions, ReactCodeMirrorProps, ReactCodeMirrorRef import { EditorView } from 'codemirror'; import { Ref, useMemo } from 'react'; -import { useConceptTheme } from '../../../context/ThemeContext'; +import { useConceptTheme } from '../../context/ThemeContext'; const editorSetup: BasicSetupOptions = { highlightSpecialChars: true, diff --git a/rsconcept/frontend/src/components/RSInput/highlight.ts b/rsconcept/frontend/src/components/RSInput/highlight.ts new file mode 100644 index 00000000..27746107 --- /dev/null +++ b/rsconcept/frontend/src/components/RSInput/highlight.ts @@ -0,0 +1,7 @@ +import {styleTags, tags} from '@lezer/highlight'; + +export const highlighting = styleTags({ + Identifier: tags.name, + Number: tags.number, + String: tags.string +}); \ No newline at end of file diff --git a/rsconcept/frontend/src/components/RSInput/rslang.grammar b/rsconcept/frontend/src/components/RSInput/rslang.grammar new file mode 100644 index 00000000..aa478c22 --- /dev/null +++ b/rsconcept/frontend/src/components/RSInput/rslang.grammar @@ -0,0 +1,20 @@ +@top Program { expression* } + +@skip { space } + +expression { + Identifier | + String | + Application { "(" expression* ")" } +} + +@tokens { + space { @whitespace+ } + Identifier { $[a-zA-Z_\-0-9]+ } + String { '"' (!["\\] | "\\" _)* '"' } + "(" ")" +} + +@detectDelim + +@external propSource highlighting from "./highlight.ts" \ No newline at end of file diff --git a/rsconcept/frontend/src/components/RSInput/rslangparser.terms.ts b/rsconcept/frontend/src/components/RSInput/rslangparser.terms.ts new file mode 100644 index 00000000..2e607541 --- /dev/null +++ b/rsconcept/frontend/src/components/RSInput/rslangparser.terms.ts @@ -0,0 +1,5 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +export const + Program = 1, + Identifier = 2, + String = 3 diff --git a/rsconcept/frontend/src/components/RSInput/rslangparser.ts b/rsconcept/frontend/src/components/RSInput/rslangparser.ts new file mode 100644 index 00000000..4f74c8be --- /dev/null +++ b/rsconcept/frontend/src/components/RSInput/rslangparser.ts @@ -0,0 +1,22 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +import {LRParser} from "@lezer/lr" +import {highlighting} from "./highlight.ts" +export const parser = LRParser.deserialize({ + version: 14, + states: "!WQVQPOOObQPO'#CbOOQO'#Cg'#CgOOQO'#Cc'#CcQVQPOOOOQO,58|,58|OpQPO,58|OOQO-E6a-E6aOOQO1G.h1G.h", + stateData: "!O~OYOS~OQQORQOTPO~OQQORQOSTOTPO~OQQORQOSWOTPO~O", + goto: "s[PPPPPP]cPPPmXQOPSUQSOQUPTVSUXROPSU", + nodeNames: "⚠ Program Identifier String ) ( Application", + maxTerm: 11, + nodeProps: [ + ["openedBy", 4,"("], + ["closedBy", 5,")"] + ], + propSources: [highlighting], + skippedNodes: [0], + repeatNodeCount: 1, + tokenData: "%[~RbX^!Zpq!Zrs#Oxy$lyz$q}!O$v!Q![$v!c!}$v#R#S$v#T#o$v#y#z!Z$f$g!Z#BY#BZ!Z$IS$I_!Z$I|$JO!Z$JT$JU!Z$KV$KW!Z&FU&FV!Z~!`YY~X^!Zpq!Z#y#z!Z$f$g!Z#BY#BZ!Z$IS$I_!Z$I|$JO!Z$JT$JU!Z$KV$KW!Z&FU&FV!Z~#RVOr#Ors#hs#O#O#O#P#m#P;'S#O;'S;=`$f<%lO#O~#mOR~~#pRO;'S#O;'S;=`#y;=`O#O~#|WOr#Ors#hs#O#O#O#P#m#P;'S#O;'S;=`$f;=`<%l#O<%lO#O~$iP;=`<%l#O~$qOT~~$vOS~~${TQ~}!O$v!Q![$v!c!}$v#R#S$v#T#o$v", + tokenizers: [0], + topRules: {"Program":[0,1]}, + tokenPrec: 0 +}) diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/textEditing.ts b/rsconcept/frontend/src/components/RSInput/textEditing.ts similarity index 99% rename from rsconcept/frontend/src/pages/RSFormPage/elements/textEditing.ts rename to rsconcept/frontend/src/components/RSInput/textEditing.ts index 772462ad..8e90fa04 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/textEditing.ts +++ b/rsconcept/frontend/src/components/RSInput/textEditing.ts @@ -2,7 +2,7 @@ import { ReactCodeMirrorRef } from '@uiw/react-codemirror'; -import { TokenID } from '../../../utils/enums'; +import { TokenID } from '../../utils/enums'; export function getSymbolSubstitute(input: string): string | undefined { switch (input) { diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression.tsx index b62330c0..3fa6df1d 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression.tsx @@ -4,17 +4,17 @@ 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 RSInput from './elements/RSInput'; import RSLocalButton from './elements/RSLocalButton'; import RSTokenButton from './elements/RSTokenButton'; import StatusBar from './elements/StatusBar'; -import { getSymbolSubstitute, TextWrapper } from './elements/textEditing'; interface EditorRSExpressionProps { id: string