syntact highlighting

main
Paul Schneider 10 months ago
parent 3ced6adbd4
commit e253fc562d
9 changed files with 157 additions and 16 deletions

@ -5,7 +5,7 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": ".NET Core Launch (console)", "name": ".NET Core Launch red sample",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "build",

@ -4,6 +4,7 @@ using System.Data;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Irony.Ast;
using Irony.Interpreter.Ast; using Irony.Interpreter.Ast;
using Irony.Parsing; using Irony.Parsing;
@ -12,6 +13,8 @@ namespace irules.core
[Language("IRule", "0.1", "Clauses grammar.")] [Language("IRule", "0.1", "Clauses grammar.")]
public class ClauseGrammar : Grammar public class ClauseGrammar : Grammar
{ {
private readonly IdOptions idoptions;
public ClauseGrammar() public ClauseGrammar()
{ {
var comment = new CommentTerminal("comment", "#", "\n"); var comment = new CommentTerminal("comment", "#", "\n");
@ -23,11 +26,12 @@ namespace irules.core
NonTerminal idOrRelation = new NonTerminal("idOrRelation"); NonTerminal idOrRelation = new NonTerminal("idOrRelation");
NonTerminal SOrOr = new NonTerminal("SOrOr"); NonTerminal SOrOr = new NonTerminal("SOrOr");
IdentifierTerminal id = new IdentifierTerminal("Id"); IdentifierTerminal id = new IdentifierTerminal("Id");
var orExpr = new NonTerminal("OrExpr", typeof(BinaryOperationNode)); var orExpr = new NonTerminal("OrExpr", typeof(BinaryOperationNode));
var andExpr = new NonTerminal("AndExpr", typeof(BinaryOperationNode)); var andExpr = new NonTerminal("AndExpr", typeof(BinaryOperationNode));
var neg = new NonTerminal("Negation", typeof(UnaryOperationNode)) var neg = new NonTerminal("Negation", typeof(UnaryOperationNode))
{ {
Rule = "^" + andExpr + ReduceHere() Rule = "^" + singleByOr + ReduceHere()
}; };
expr.Rule = "(" + expr + ")" | SOrOr ; expr.Rule = "(" + expr + ")" | SOrOr ;
SOrOr.Rule = orExpr | singleByOr; SOrOr.Rule = orExpr | singleByOr;
@ -40,6 +44,7 @@ namespace irules.core
RegisterBracePair("(", ")"); RegisterBracePair("(", ")");
RegisterOperators(30, "&|^"); RegisterOperators(30, "&|^");
Root = expr; Root = expr;
} }
} }
} }

@ -1,3 +1,4 @@
using System.Runtime.InteropServices;
using Irony.Interpreter; using Irony.Interpreter;
using Irony.Parsing; using Irony.Parsing;
@ -5,6 +6,10 @@ namespace irules.core
{ {
public class ClauseChecker public class ClauseChecker
{ {
public TokenList LastScriptTokens => app.LastScript?.Tokens;
public ParseTree LatestParsedTree { get; private set; }
ScriptApp app; ScriptApp app;
public ClauseChecker() public ClauseChecker()
{ {
@ -14,9 +19,11 @@ namespace irules.core
app = new ScriptApp(r); app = new ScriptApp(r);
} }
public virtual AppStatus Parse(string problem) public virtual AppStatus Parse(string problem)
{ {
app.Evaluate(problem); LatestParsedTree = app.Parser.Parse(problem);
try { try {
switch (app.Status) switch (app.Status)
{ {

@ -27,7 +27,7 @@ public partial class App : Application
{ {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
desktop.MainWindow = new MainWindow(); desktop.MainWindow = new MainWindow(checker);
} }
base.OnFrameworkInitializationCompleted(); base.OnFrameworkInitializationCompleted();

@ -0,0 +1,13 @@
using AvaloniaEdit.Document;
using AvaloniaEdit.Rendering;
namespace red
{
internal class IronyGrammarTransformer : DocumentColorizingTransformer
{
protected override void ColorizeLine(DocumentLine line)
{
throw new System.NotImplementedException();
}
}
}

@ -11,15 +11,17 @@
<DockPanel> <DockPanel>
<Menu DockPanel.Dock="Top"> <Menu DockPanel.Dock="Top">
<MenuItem Header="_File"> <MenuItem Header="_File">
<MenuItem Header="_Open..." Click="OnOpen"/> <MenuItem Header="_Open ..." Click="OnOpen"/>
<MenuItem Header="_Save" Click="OnSave"/>
<MenuItem Header="Save _To ..." Click="OnSaveTo"/>
<Separator /> <Separator />
<MenuItem Header="_Exit" Click="OnExit"/> <MenuItem Header="_Exit" Click="OnExit"/>
</MenuItem> </MenuItem>
<MenuItem Header="_Edit"> <MenuItem Header="_Edit">
<MenuItem Header="Copy" /> <MenuItem Header="Copy" HotKey="Ctrl+C" />
<MenuItem Header="Paste" /> <MenuItem Header="Paste" HotKey="Ctrl+V"/>
</MenuItem> </MenuItem>
<MenuItem Header="_Run"> <MenuItem Header="_Run" Click="OnRun">
</MenuItem> </MenuItem>
</Menu> </Menu>
<StackPanel DockPanel.Dock="Bottom"> <StackPanel DockPanel.Dock="Bottom">

@ -1,32 +1,128 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.Rendering;
using Avalonia.Threading;
using Avalonia.VisualTree;
using AvaloniaEdit;
using AvaloniaEdit.Highlighting;
using AvaloniaEdit.Rendering;
using Irony.Interpreter;
using Irony.Parsing;
using irules.core;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Avalonia.Media;
namespace red; namespace red;
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
public MainWindow() ClauseChecker checker;
public MainWindow(ClauseChecker checker)
{ {
this.checker = checker;
InitializeComponent(); InitializeComponent();
SetupTheme();
src.Text = "Hello !"; src.Text = "Hello !";
src.TextChanged += OnTextChanged;
src.TextArea.TextView.VisualLinesChanged += TextView_VisualLinesChanged;
} }
private void TextView_VisualLinesChanged(object sender, EventArgs e)
{
//throw new NotImplementedException();
}
private void SetupTheme()
{
HighlightingColor keywork = new HighlightingColor
{ Foreground = new SimpleHighlightingBrush(Color.FromRgb(255,155,50)) };
HighlightingColor comment = new HighlightingColor
{ FontStyle = Avalonia.Media.FontStyle.Italic,
Foreground = new SimpleHighlightingBrush(Color.FromRgb(150,150,150)) };
HighlightingColor identifier = new HighlightingColor
{ Foreground = new SimpleHighlightingBrush(Color.FromRgb(255,195,255)) };
ColorTheme = new Dictionary<TokenColor, HighlightingColor>
{
{ TokenColor.Text, keywork},
{ TokenColor.Keyword, keywork},
{ TokenColor.Comment, comment},
{ TokenColor.Identifier, identifier},
{ TokenColor.String, comment},
{ TokenColor.Number, identifier}
};
}
Dictionary<TokenColor, HighlightingColor> ColorTheme;
private void OnTextChanged(object sender, EventArgs e)
{
var appstatus = checker.Parse(src.Text);
statusMessage.Text = "Parsing :" +
appstatus.ToString();
switch (appstatus)
{
case AppStatus.Ready:
case AppStatus.SyntaxError:
case AppStatus.WaitingMoreInput:
src.TextArea.TextView.LineTransformers.Clear();
RichTextModel model = new RichTextModel();
checker.LatestParsedTree.Tokens?.ForEach (
token =>
{
switch(token.Category)
{
case TokenCategory.Error:
case TokenCategory.Directive:
case TokenCategory.Content:
case TokenCategory.Comment:
// token.Location.Line
model.ApplyHighlighting(token.Location.Position, token.Length,
ColorTheme[token.EditorInfo.Color]);
break;
}
});
transformer = new RichTextColorizer(model);
src.TextArea.TextView.LineTransformers.Add(transformer);
break;
}
}
public void OnExit(object sender, RoutedEventArgs e) public void OnExit(object sender, RoutedEventArgs e)
{ {
Close(); Close();
} }
string sourceFileName=null;
private ITextRunConstructionContext context;
private RichTextColorizer transformer;
private ITextRunConstructionContext transformerContext;
public void OnOpen(object sender, RoutedEventArgs e) public void OnOpen(object sender, RoutedEventArgs e)
{ {
Task.Run(async () => Task.Run(async () =>
{ {
FilePickerOpenOptions options = new FilePickerOpenOptions FilePickerOpenOptions options = new FilePickerOpenOptions
{ {
AllowMultiple = true, AllowMultiple = false,
Title = "Red" Title = "Open a red file"
}; };
options.FileTypeFilter = new FilePickerFileType[] options.FileTypeFilter = new FilePickerFileType[]
{ new("red"){ Patterns = new string[] { "*.red" } } }; { new("red"){ Patterns = new string[] { "*.red" } } };
@ -35,11 +131,27 @@ public partial class MainWindow : Window
if (result != null) if (result != null)
{ {
foreach (var item in result) var item = result.First();
{ sourceFileName =
System.Diagnostics.Debug.WriteLine($"Opened: {item.Path}"); item.Path.AbsolutePath;
} Dispatcher.UIThread.Post(() => src.Text = File.ReadAllText(sourceFileName));
System.Diagnostics.Debug.WriteLine($"Opened: {sourceFileName}");
} }
}); });
} }
public void OnSave(object sender, RoutedEventArgs e)
{
if (sourceFileName==null) OnSaveTo(sender, e);
File.WriteAllText(sourceFileName, src.Text);
}
public void OnSaveTo(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
public void OnRun(object sender, RoutedEventArgs e)
{
}
} }

@ -21,6 +21,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.5" /> <PackageReference Include="Avalonia" Version="11.0.5" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.5" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.5" /> <PackageReference Include="Avalonia.Desktop" Version="11.0.5" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.5" /> <PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.5" />
@ -29,7 +30,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.0.5" /> <PackageReference Include="Avalonia.AvaloniaEdit" Version="11.0.5" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.0.5" />
<ProjectReference Include="../../irules.core/irules.core.csproj" /> <ProjectReference Include="../../irules.core/irules.core.csproj" />

Loading…