From d2bf3a6af6aa441d39291be61ed6cf9c02d47a00 Mon Sep 17 00:00:00 2001 From: Emil Krebs Date: Tue, 5 Dec 2023 17:03:47 +0100 Subject: [PATCH 01/14] initial changes --- hugo/assets/scripts/minilogo/minilogo.tsx | 67 +- hugo/content/playground/Tree.tsx | 54 +- hugo/content/playground/_index.html | 34 +- hugo/content/playground/common.ts | 41 +- hugo/content/playground/langium-worker.ts | 8 +- hugo/content/playground/preprocess.ts | 59 ++ hugo/layouts/playground/baseof.html | 545 ++++++------- hugo/package.json | 3 +- package-lock.json | 909 +++++++++++++++++++++- 9 files changed, 1386 insertions(+), 334 deletions(-) diff --git a/hugo/assets/scripts/minilogo/minilogo.tsx b/hugo/assets/scripts/minilogo/minilogo.tsx index 3f39c923..2d7a3f4d 100644 --- a/hugo/assets/scripts/minilogo/minilogo.tsx +++ b/hugo/assets/scripts/minilogo/minilogo.tsx @@ -19,6 +19,7 @@ let shouldAnimate = true; interface PreviewProps { commands?: Command[]; diagnostics?: Diagnostic[]; + hidden?: boolean; } interface DrawCanvasProps { @@ -157,11 +158,13 @@ class DrawCanvas extends React.Component { } class Preview extends React.Component { canvasRef: React.RefObject; + hidden: boolean; constructor(props: PreviewProps) { super(props); this.state = { commands: props.commands, diagnostics: props.diagnostics, + hidden: false, }; this.canvasRef = createRef(); this.startPreview = this.startPreview.bind(this); @@ -171,7 +174,24 @@ class Preview extends React.Component { this.setState({ commands, diagnostics }); } + hide() { + this.setState({ hidden: true }); + } + + show() { + this.setState({ hidden: false }); + } + + isHidden(): boolean { + return this.hidden; + } + render() { + if (this.props.hidden) { + return; + } + + // check if code contains an astNode if (!this.state.commands) { // Show the exception @@ -210,12 +230,15 @@ class Preview extends React.Component { interface AppState { currentExample: number; + currentWindow: 'preview' | 'editor'; } class App extends React.Component<{}, AppState> { monacoEditor: React.RefObject; preview: React.RefObject; copyHint: React.RefObject; shareButton: React.RefObject; + + constructor(props) { super(props); @@ -230,6 +253,7 @@ class App extends React.Component<{}, AppState> { this.state = { currentExample: 0, + currentWindow: 'editor' }; } @@ -306,32 +330,56 @@ class App extends React.Component<{}, AppState> {
- Editor + Editor
+
+ {/* Button to switch between preview and editor */} + +
Link was copied!
- +
+ +
+
+
+
-
+
Preview
- +
@@ -357,3 +405,4 @@ userConfig = createUserConfig({ }); const root = createRoot(document.getElementById("root") as HTMLElement); root.render(); + \ No newline at end of file diff --git a/hugo/content/playground/Tree.tsx b/hugo/content/playground/Tree.tsx index 2b15c1fd..38bf2c42 100644 --- a/hugo/content/playground/Tree.tsx +++ b/hugo/content/playground/Tree.tsx @@ -7,20 +7,51 @@ import { AstNode } from "langium"; import React, { FC, useState } from "react"; import * as ReactDOM from "react-dom/client"; -import { preprocessAstNodeObject, PropertyNode, ValueNode } from "./preprocess"; +import { preprocessAstNodeObject, preprocessAstNodeToForceGraphData, PropertyNode, ValueNode } from "./preprocess"; import { clsx } from "clsx"; import { AstNodeLocator } from "langium/lib/workspace/ast-node-locator"; +import { ForceGraph3D } from 'react-force-graph'; +import { convertASTtoGraph } from "langium-ast-helper"; export let treeRoot: ReactDOM.Root; +export type CurrentTreeWindow = "ast" | "grammar"; -export function render(root: AstNode, locator: AstNodeLocator) { +export function render(root: AstNode, locator: AstNodeLocator, currentWindow: CurrentTreeWindow, grammar?: AstNode) { const location = document.getElementById("ast-body")!; const data = preprocessAstNodeObject(root, locator); + if (!treeRoot) { // create a fresh root, if not already present treeRoot = ReactDOM.createRoot(location); } - treeRoot.render( + + // check if the user wants the visualization to be interactive + if (currentWindow === "grammar" && grammar) { + const graphData = convertASTtoGraph(grammar); + + const gData = { + nodes: graphData.nodes.map(node => ({ + id: (node as unknown as { $__dotID: string }).$__dotID, + nodeType: node.$type, + nodeLabel: node, + node + })), + links: graphData.edges.map(edge => ({ + source: (edge.from as unknown as { $__dotID: string }).$__dotID, + target: (edge.to as unknown as { $__dotID: string }).$__dotID + })) + }; + + return treeRoot.render( + + ); + + } + + // generate the interactive tree + return treeRoot.render(
@@ -44,13 +75,13 @@ const TreeContent: FC = ({ root, hidden }) => { case "number": case "string": return ( - - {hidden - ? "..." - : root.kind === "string" + + {hidden + ? "..." + : root.kind === "string" ? '"' + root.value + '"' : root.value.toString()} - + ); case "object": return ( @@ -77,10 +108,10 @@ const TreeContent: FC = ({ root, hidden }) => { ); case "array": - if(root.children.length === 0) { + if (root.children.length === 0) { return {"[]"} } - if(hidden) { + if (hidden) { return {"[...]"} } return ( @@ -108,7 +139,7 @@ const TreeContent: FC = ({ root, hidden }) => { return ( <> {hidden ? {"Reference(...)"} : - Reference('{root.$text}')} + Reference('{root.$text}')} ); } @@ -125,6 +156,7 @@ const TreeNode: FC = ({ root, hidden }) => { function Property({ p, comma }: { p: PropertyNode; comma: boolean }) { const [open, setOpen] = useState(true); + return (
  • diff --git a/hugo/content/playground/_index.html b/hugo/content/playground/_index.html index d005d41b..da5257e9 100644 --- a/hugo/content/playground/_index.html +++ b/hugo/content/playground/_index.html @@ -10,11 +10,11 @@ noMain: true playground: true --- - - - + + +