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