diff --git a/Canon.Server/Canon.Server.csproj b/Canon.Server/Canon.Server.csproj index ba4ea49..649e259 100644 --- a/Canon.Server/Canon.Server.csproj +++ b/Canon.Server/Canon.Server.csproj @@ -17,12 +17,13 @@ + + - diff --git a/Canon.Visualization/Models/Brush.cs b/Canon.Server/Models/Brush.cs similarity index 97% rename from Canon.Visualization/Models/Brush.cs rename to Canon.Server/Models/Brush.cs index 4cab954..3119086 100644 --- a/Canon.Visualization/Models/Brush.cs +++ b/Canon.Server/Models/Brush.cs @@ -1,6 +1,6 @@ using SkiaSharp; -namespace Canon.Visualization.Models; +namespace Canon.Server.Models; public sealed class Brush(SKCanvas canvas) : IDisposable { diff --git a/Canon.Visualization/Models/PresentableTreeNode.cs b/Canon.Server/Models/PresentableTreeNode.cs similarity index 99% rename from Canon.Visualization/Models/PresentableTreeNode.cs rename to Canon.Server/Models/PresentableTreeNode.cs index 562664d..851ecbe 100644 --- a/Canon.Visualization/Models/PresentableTreeNode.cs +++ b/Canon.Server/Models/PresentableTreeNode.cs @@ -1,7 +1,7 @@ using Canon.Core.SyntaxNodes; using SkiaSharp; -namespace Canon.Visualization.Models; +namespace Canon.Server.Models; /// /// 展示树节点 @@ -9,7 +9,7 @@ namespace Canon.Visualization.Models; /// public class PresentableTreeNode { - public float X { get; set; } = -1; + public float X { get; set; } public float Y { get; set; } public SKPoint Position => new(X, Y); diff --git a/Canon.Server/Program.cs b/Canon.Server/Program.cs index 0be77b2..4fe11c7 100644 --- a/Canon.Server/Program.cs +++ b/Canon.Server/Program.cs @@ -2,7 +2,6 @@ using Canon.Core.Abstractions; using Canon.Core.LexicalParser; using Canon.Server.Extensions; using Canon.Server.Services; -using Canon.Visualization.Services; using Microsoft.EntityFrameworkCore; WebApplicationBuilder builder = WebApplication.CreateBuilder(args); diff --git a/Canon.Server/Services/CompilerService.cs b/Canon.Server/Services/CompilerService.cs index 017b4c9..840b0fd 100644 --- a/Canon.Server/Services/CompilerService.cs +++ b/Canon.Server/Services/CompilerService.cs @@ -2,7 +2,6 @@ using Canon.Core.LexicalParser; using Canon.Core.SyntaxNodes; using Canon.Server.Models; -using Canon.Visualization.Services; using Microsoft.EntityFrameworkCore; namespace Canon.Server.Services; diff --git a/Canon.Server/Services/SyntaxTreePresentationService.cs b/Canon.Server/Services/SyntaxTreePresentationService.cs new file mode 100644 index 0000000..cae39e8 --- /dev/null +++ b/Canon.Server/Services/SyntaxTreePresentationService.cs @@ -0,0 +1,89 @@ +using Canon.Core.SyntaxNodes; +using Canon.Server.Models; +using SkiaSharp; + +namespace Canon.Server.Services; + +public class SyntaxTreePresentationService +{ + private const float Scale = 150; + + public Stream Present(ProgramStruct root) + { + PresentableTreeNode presentableTreeRoot = PresentableTreeNode.Build(root); + ScaleTree(presentableTreeRoot); + + (float height, float width) = presentableTreeRoot.CalculateImageSize(); + using SKSurface surface = SKSurface.Create( + new SKImageInfo((int)(width + 2 * Scale), (int)(height * Scale))); + + surface.Canvas.Clear(SKColors.White); + + using Brush brush = new(surface.Canvas); + DrawNode(presentableTreeRoot, brush); + + using SKImage image = surface.Snapshot(); + SKData data = image.Encode(); + + return data.AsStream(); + } + + private void DrawNode(PresentableTreeNode node, Brush brush) + { + foreach (PresentableTreeNode child in node.Children) + { + brush.DrawLine(node.Position, child.Position); + DrawNode(child, brush); + } + + brush.DrawText(node.Position, node.DisplayText); + } + + private void ScaleTree(PresentableTreeNode root) + { + Queue queue = []; + queue.Enqueue(root); + float minX = float.MaxValue; + + // 第一次遍历 + // 放大坐标并获得最左侧的节点X坐标 + while (queue.Count != 0) + { + PresentableTreeNode node = queue.Dequeue(); + + node.X *= Scale; + node.X += Scale; + node.Y *= Scale; + node.Y += Scale; + + minX = float.Min(minX, node.X); + + foreach (PresentableTreeNode child in node.Children) + { + queue.Enqueue(child); + } + } + + if (minX >= Scale) + { + // 判断最左侧的节点位置是否正确 + return; + } + + float delta = Scale - minX; + + // 第二次遍历调整位置 + queue.Enqueue(root); + while (queue.Count != 0) + { + PresentableTreeNode node = queue.Dequeue(); + + node.X += delta; + + foreach (PresentableTreeNode child in node.Children) + { + queue.Enqueue(child); + } + } + } +} diff --git a/Canon.Server/client-app/package.json b/Canon.Server/client-app/package.json index e92b3a5..c5f594b 100644 --- a/Canon.Server/client-app/package.json +++ b/Canon.Server/client-app/package.json @@ -15,6 +15,7 @@ "@fontsource/roboto": "^5.0.12", "@mui/icons-material": "^5.15.14", "@mui/material": "^5.15.14", + "notistack": "^3.0.1", "openapi-fetch": "^0.9.3", "openapi-typescript": "^6.7.5", "react": "^18.2.0", diff --git a/Canon.Server/client-app/src/Pages/Index.tsx b/Canon.Server/client-app/src/Pages/Index.tsx index 0c06fb5..592117b 100644 --- a/Canon.Server/client-app/src/Pages/Index.tsx +++ b/Canon.Server/client-app/src/Pages/Index.tsx @@ -4,6 +4,7 @@ import {CSSProperties, useState} from "react"; import {OutputField} from "./OutputField.tsx"; import createClient from "openapi-fetch"; import * as openapi from '../openapi'; +import {enqueueSnackbar} from "notistack"; const client = createClient(); @@ -23,6 +24,7 @@ export function Index() { id: "", imageAddress: "pic/uncompiled.png" }); + //const {enqueueSnackbar} = useSnackbar(); const handleValueChange = (value: string) => { setInputValue(value); }; @@ -43,6 +45,10 @@ export function Index() { id: data.id, imageAddress: data.imageAddress }) + enqueueSnackbar("编译成功", {variant: "success", anchorOrigin: {vertical: 'top', horizontal: 'right'}}); + } else { + // error + enqueueSnackbar("编译失败", {variant: "error", anchorOrigin: {vertical: 'top', horizontal: 'right'}}); } } @@ -72,12 +78,12 @@ export function Index() {
- - + + - + diff --git a/Canon.Server/client-app/src/main.tsx b/Canon.Server/client-app/src/main.tsx index 3b2c0fd..98bae55 100644 --- a/Canon.Server/client-app/src/main.tsx +++ b/Canon.Server/client-app/src/main.tsx @@ -1,15 +1,17 @@ import React from 'react' import ReactDOM from 'react-dom/client' -import { App } from './App.tsx' +import {App} from './App.tsx' import '@fontsource/roboto/300.css'; import '@fontsource/roboto/400.css'; import '@fontsource/roboto/500.css'; import '@fontsource/roboto/700.css'; -import { CssBaseline } from '@mui/material'; +import {CssBaseline} from '@mui/material'; +import {SnackbarProvider} from "notistack"; ReactDOM.createRoot(document.getElementById('root')!).render( - - - - , + + + + + , ) diff --git a/Canon.Tests/Canon.Tests.csproj b/Canon.Tests/Canon.Tests.csproj index 5566a72..bd9c5c3 100644 --- a/Canon.Tests/Canon.Tests.csproj +++ b/Canon.Tests/Canon.Tests.csproj @@ -24,7 +24,6 @@ - diff --git a/Canon.Tests/GrammarParserTests/PascalGrammarTests.cs b/Canon.Tests/GrammarParserTests/PascalGrammarTests.cs index c9536bd..0cccbee 100644 --- a/Canon.Tests/GrammarParserTests/PascalGrammarTests.cs +++ b/Canon.Tests/GrammarParserTests/PascalGrammarTests.cs @@ -84,8 +84,9 @@ public class PascalGrammarTests { const string program = """ program varTest; - var a : char; + var a : integer; begin + a := 9 div 1; end. """; diff --git a/Canon.Visualization/Canon.Visualization.csproj b/Canon.Visualization/Canon.Visualization.csproj deleted file mode 100644 index 56ac0e6..0000000 --- a/Canon.Visualization/Canon.Visualization.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - net8.0 - enable - enable - - - - - - - - - - - - diff --git a/Canon.Visualization/Services/SyntaxTreePresentationService.cs b/Canon.Visualization/Services/SyntaxTreePresentationService.cs deleted file mode 100644 index 51fa2e0..0000000 --- a/Canon.Visualization/Services/SyntaxTreePresentationService.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Canon.Core.SyntaxNodes; -using Canon.Visualization.Models; -using SkiaSharp; - -namespace Canon.Visualization.Services; - -public class SyntaxTreePresentationService -{ - private const float Scale = 150; - - public Stream Present(ProgramStruct root) - { - PresentableTreeNode presentableTreeRoot = PresentableTreeNode.Build(root); - ScaleTree(presentableTreeRoot); - - (float height, float width) = presentableTreeRoot.CalculateImageSize(); - using SKSurface surface = SKSurface.Create( - new SKImageInfo((int)(width + 2 * Scale), (int)(height * Scale))); - - surface.Canvas.Clear(SKColors.White); - - using Brush brush = new(surface.Canvas); - DrawNode(presentableTreeRoot, brush); - - using SKImage image = surface.Snapshot(); - SKData data = image.Encode(); - - return data.AsStream(); - } - - private void DrawNode(PresentableTreeNode node, Brush brush) - { - foreach (PresentableTreeNode child in node.Children) - { - brush.DrawLine(node.Position, child.Position); - DrawNode(child, brush); - } - - brush.DrawText(node.Position, node.DisplayText); - } - - private void ScaleTree(PresentableTreeNode node) - { - node.X *= Scale; - node.X += Scale; - node.Y *= Scale; - node.Y += Scale; - - foreach (PresentableTreeNode child in node.Children) - { - ScaleTree(child); - } - } -} diff --git a/Canon.sln b/Canon.sln index 13edb63..db33a87 100644 --- a/Canon.sln +++ b/Canon.sln @@ -26,8 +26,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .gitea\workflows\build.yaml = .gitea\workflows\build.yaml EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Canon.Visualization", "Canon.Visualization\Canon.Visualization.csproj", "{23644467-2BCB-422D-8942-C20AF4A7F429}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Canon.Server", "Canon.Server\Canon.Server.csproj", "{401112EA-1A87-4D1C-9B6D-085309F4137E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Canon.Generator", "Canon.Generator\Canon.Generator.csproj", "{32C103C4-589C-4DC2-B173-55B1799B62CE}" @@ -53,10 +51,6 @@ Global {E5F2B97B-3766-466D-9309-BA361F0CE15E}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5F2B97B-3766-466D-9309-BA361F0CE15E}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5F2B97B-3766-466D-9309-BA361F0CE15E}.Release|Any CPU.Build.0 = Release|Any CPU - {23644467-2BCB-422D-8942-C20AF4A7F429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {23644467-2BCB-422D-8942-C20AF4A7F429}.Debug|Any CPU.Build.0 = Debug|Any CPU - {23644467-2BCB-422D-8942-C20AF4A7F429}.Release|Any CPU.ActiveCfg = Release|Any CPU - {23644467-2BCB-422D-8942-C20AF4A7F429}.Release|Any CPU.Build.0 = Release|Any CPU {401112EA-1A87-4D1C-9B6D-085309F4137E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {401112EA-1A87-4D1C-9B6D-085309F4137E}.Debug|Any CPU.Build.0 = Debug|Any CPU {401112EA-1A87-4D1C-9B6D-085309F4137E}.Release|Any CPU.ActiveCfg = Release|Any CPU