using FastReport.Design.PageDesigners.Code; using FastReport.Engine; using FastReport.Utils; using Microsoft.CodeAnalysis; using RoslynPad.Editor; using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace FastReport.WPF.RoslynPad { internal class RoslynPadSyntaxEditor : SyntaxEditorBase { private RoslynCodeEditor editor; private Report report; private MyRoslynHost _host; private string oldPartialClass; public override string Text { get => RemovePartialKeyword(editor.Text); set => editor.Text = AddPartialKeyword(value); } public override string SelectedText { get => editor.SelectedText; set => editor.SelectedText = value; } public override bool Modified { get => editor.IsModified; set => editor.IsModified = value; } public override bool ShowLineNumbers { get => editor.ShowLineNumbers; set => editor.ShowLineNumbers = value; } public override bool EnableVirtualSpace { get => editor.Options.EnableVirtualSpace; set => editor.Options.EnableVirtualSpace = value; } public override bool ConvertTabsToSpaces { get => editor.Options.ConvertTabsToSpaces; set => editor.Options.ConvertTabsToSpaces = value; } public override int IndentationSize { get => editor.Options.IndentationSize; set => editor.Options.IndentationSize = value; } private SyntaxType syntaxType; public override SyntaxType SyntaxType { get => syntaxType; set { if (syntaxType != value) { syntaxType = value; InitDocument(); } } } public override bool AllowCodeCompletion { get; set; } public override void Cut() => editor.Cut(); public override void Copy() => editor.Copy(); public override void Paste() => editor.Paste(); public override bool CanUndo => editor.CanUndo; public override void Undo() => editor.Undo(); public override bool CanRedo => editor.CanRedo; public override void Redo() => editor.Redo(); public override void Select(int start, int length) => editor.Select(start, length); public override void SelectAll() => editor.SelectAll(); public override void Focus() { Application.DoEvents(); editor.Dispatcher.InvokeAsync(() => editor.Focus()); } public override void Locate(int line, int column) { editor.CaretOffset = editor.Document.GetOffset(line, column); } public override void SetCaretFromMousePosition(System.Drawing.Point pos) { var textPos = editor.GetPositionFromPoint(new System.Windows.Point(pos.X / DpiScale, pos.Y / DpiScale)); if (textPos != null) { Locate(textPos.Value.Line, textPos.Value.Column); } } public override void UpdateInternals(Report report) { this.report = report; string partialClass = MakePartialClass(); if (partialClass != oldPartialClass) { oldPartialClass = partialClass; _host.SetAdditionalInfo(partialClass, report.ReferencedAssemblies); } } private void InitDocument() { _host = new MyRoslynHost(SyntaxType); editor.InitializeAsync(_host, new ClassificationHighlightColors(), Directory.GetCurrentDirectory(), string.Empty, SourceCodeKind.Regular); } private string MakePartialClass() { ObjectCollection allObjects = report.AllObjects; SortedList objects = new SortedList(); StringBuilder partialClass = new StringBuilder(1000); AddClassHeader(partialClass); // add all report objects AddObject(partialClass, typeof(Report), "Report"); AddObject(partialClass, typeof(ReportEngine), "Engine"); foreach (Base c in allObjects) { if (!String.IsNullOrEmpty(c.Name) && !objects.ContainsKey(c.Name)) objects.Add(c.Name, c); } foreach (Base c in objects.Values) { AddObject(partialClass, c.GetType(), c.Name); } AddClassFooter(partialClass); return partialClass.ToString(); } private void AddClassHeader(StringBuilder text) { if (SyntaxType == SyntaxType.Cs) { text.AppendLine("namespace FastReport {"); text.AppendLine("partial class ReportScript {"); } else { text.AppendLine("Namespace FastReport"); text.AppendLine("Partial Class ReportScript"); } } private void AddClassFooter(StringBuilder text) { if (SyntaxType == SyntaxType.Cs) { text.AppendLine("}}"); } else { text.AppendLine("End Class"); text.AppendLine("End Namespace"); } } private void AddObject(StringBuilder text, Type type, string name) { if (SyntaxType == SyntaxType.Cs) { text.Append("public ").Append(type.FullName).Append(" ").Append(name).Append(";\r\n"); } else { text.Append("public ").Append(name).Append(" as Global.").Append(type.FullName).Append("\r\n"); } } private string AddPartialKeyword(string value) { if (SyntaxType == SyntaxType.Cs) { return value.Replace("public class ReportScript", "public partial class ReportScript"); } return value.Replace("Public Class ReportScript", "Public Partial Class ReportScript"); } private string RemovePartialKeyword(string value) { if (SyntaxType == SyntaxType.Cs) { return value.Replace("public partial class ReportScript", "public class ReportScript"); } return value.Replace("Public Partial Class ReportScript", "Public Class ReportScript"); } public RoslynPadSyntaxEditor() { editor = new RoslynCodeEditor(); SetControl(editor); editor.HorizontalScrollBarVisibility = editor.VerticalScrollBarVisibility = System.Windows.Controls.ScrollBarVisibility.Auto; editor.Padding = new System.Windows.Thickness(4, 2, 0, 0); editor.TextChanged += (s, e) => OnTextChanged(); } } public static class SyntaxEditor { public static void Register() { SyntaxEditorClass.Register(typeof(RoslynPadSyntaxEditor), SyntaxEditorKind.Code); Warmup(); } private static async void Warmup() { await Task.Run(() => new MyRoslynHost(SyntaxType.Cs)); } } }