using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using ColorCode; using ColorCode.Common; using ColorCode.Parsing; using ColorCode.Styling; #nullable enable namespace Szmedi.RvKits.RvScript { /// /// Creates a , for rendering Syntax Highlighted code to a RichTextBlock. /// public class RichTextBoxFormatter : CodeColorizerBase { /// /// Creates a , for rendering Syntax Highlighted code to a RichTextBlock. /// /// The Custom styles to Apply to the formatted Code. /// The language parser that the instance will use for its lifetime. public RichTextBoxFormatter(StyleDictionary? style = null, ILanguageParser? languageParser = null) : base(style, languageParser) { } /// /// Adds Syntax Highlighted Source Code to the provided RichTextBlock. /// /// The source code to colorize. /// The language to use to colorize the source code. /// The Control to add the Text to. public void FormatRichTextBox(string sourceCode, ILanguage language, RichTextBox richText) { var paragraph = new Paragraph(); richText.Document.Blocks.Add(paragraph); FormatInlines(sourceCode, language, paragraph.Inlines); } /// /// Adds Syntax Highlighted Source Code to the provided InlineCollection. /// /// The source code to colorize. /// The language to use to colorize the source code. /// InlineCollection to add the Text to. public void FormatInlines(string sourceCode, ILanguage language, InlineCollection inlineCollection) { InlineCollection = inlineCollection; languageParser.Parse(sourceCode, language, (parsedSourceCode, captures) => Write(parsedSourceCode, captures)); } private InlineCollection? InlineCollection { get; set; } protected override void Write(string parsedSourceCode, IList scopes) { var styleInsertions = new List(); foreach (Scope scope in scopes) GetStyleInsertionsForCapturedStyle(scope, styleInsertions); styleInsertions.SortStable((x, y) => x.Index.CompareTo(y.Index)); int offset = 0; Scope? previousScope = null; foreach (var styleinsertion in styleInsertions) { var text = parsedSourceCode.Substring(offset, styleinsertion.Index - offset); CreateSpan(text, previousScope); if (!string.IsNullOrWhiteSpace(styleinsertion.Text)) { CreateSpan(text, previousScope); } offset = styleinsertion.Index; previousScope = styleinsertion.Scope; } var remaining = parsedSourceCode.Substring(offset); // Ensures that those loose carriages don't run away! if (remaining != "\r") { CreateSpan(remaining, null); } } private void CreateSpan(string text, Scope? scope) { var span = new Span(); var run = new Run { Text = text }; // Styles and writes the text to the span. if (scope != null) StyleRun(run, scope); span.Inlines.Add(run); InlineCollection?.Add(span); } private void StyleRun(Run run, Scope scope) { string? foreground = null; string? background = null; bool italic = false; bool bold = false; if (Styles.Contains(scope.Name)) { ColorCode.Styling.Style style = Styles[scope.Name]; foreground = style.Foreground; background = style.Background; italic = style.Italic; bold = style.Bold; } if (!string.IsNullOrWhiteSpace(foreground)) run.Foreground = foreground.GetSolidColorBrush(); //Background isn't supported, but a workaround could be created. if (italic) run.FontStyle = FontStyles.Italic; if (bold) run.FontWeight = FontWeights.Bold; } private void GetStyleInsertionsForCapturedStyle(Scope scope, ICollection styleInsertions) { styleInsertions.Add(new TextInsertion { Index = scope.Index, Scope = scope }); foreach (Scope childScope in scope.Children) GetStyleInsertionsForCapturedStyle(childScope, styleInsertions); styleInsertions.Add(new TextInsertion { Index = scope.Index + scope.Length }); } } }