using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using Microsoft.Win32; namespace AxCopilot.Services; public static class MarkdownRenderer { private static readonly Regex FilePathPattern = new Regex("(?])([A-Za-z]:\\\\[^\\s<>\"',;)]+|\\.{1,2}/[\\w\\-./]+(?:\\.[a-zA-Z]{1,10})?|[\\w\\-]+(?:/[\\w\\-\\.]+){1,}(?:\\.[a-zA-Z]{1,10})?|[\\w\\-]+\\.(?:cs|py|js|ts|tsx|jsx|json|xml|html|htm|css|md|txt|yml|yaml|toml|sh|bat|ps1|csproj|sln|docx|xlsx|pptx|pdf|csv|enc|skill))(?=[,\\s;)\"'<]|$)", RegexOptions.Compiled); private static readonly Brush KeywordBrush = new SolidColorBrush(Color.FromRgb(197, 134, 192)); private static readonly Brush TypeBrush = new SolidColorBrush(Color.FromRgb(78, 201, 176)); private static readonly Brush StringBrush = new SolidColorBrush(Color.FromRgb(206, 145, 120)); private static readonly Brush CommentBrush = new SolidColorBrush(Color.FromRgb(106, 153, 85)); private static readonly Brush NumberBrush = new SolidColorBrush(Color.FromRgb(181, 206, 168)); private static readonly Brush MethodBrush = new SolidColorBrush(Color.FromRgb(220, 220, 170)); private static readonly Brush DirectiveBrush = new SolidColorBrush(Color.FromRgb(156, 220, 254)); private static readonly HashSet CSharpKeywords = new HashSet(StringComparer.Ordinal) { "abstract", "as", "async", "await", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "var", "virtual", "void", "volatile", "while", "yield", "record", "init", "required", "get", "set", "value", "where", "when", "and", "or", "not" }; private static readonly HashSet PythonKeywords = new HashSet(StringComparer.Ordinal) { "False", "None", "True", "and", "as", "assert", "async", "await", "break", "class", "continue", "def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "raise", "return", "try", "while", "with", "yield" }; private static readonly HashSet JsKeywords = new HashSet(StringComparer.Ordinal) { "abstract", "arguments", "async", "await", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default", "delete", "do", "double", "else", "enum", "eval", "export", "extends", "false", "final", "finally", "float", "for", "from", "function", "goto", "if", "implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", "null", "of", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof", "undefined", "var", "void", "volatile", "while", "with", "yield" }; private static readonly HashSet JavaKeywords = new HashSet(StringComparer.Ordinal) { "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void", "volatile", "while", "var", "record", "sealed", "permits", "yield" }; private static readonly HashSet SqlKeywords = new HashSet(StringComparer.OrdinalIgnoreCase) { "SELECT", "FROM", "WHERE", "INSERT", "INTO", "UPDATE", "SET", "DELETE", "CREATE", "DROP", "ALTER", "TABLE", "INDEX", "VIEW", "JOIN", "INNER", "LEFT", "RIGHT", "OUTER", "FULL", "CROSS", "ON", "AND", "OR", "NOT", "IN", "IS", "NULL", "LIKE", "BETWEEN", "EXISTS", "HAVING", "GROUP", "BY", "ORDER", "ASC", "DESC", "LIMIT", "OFFSET", "UNION", "ALL", "DISTINCT", "AS", "CASE", "WHEN", "THEN", "ELSE", "END", "VALUES", "PRIMARY", "KEY", "FOREIGN", "REFERENCES", "CONSTRAINT", "UNIQUE", "CHECK", "DEFAULT", "COUNT", "SUM", "AVG", "MIN", "MAX", "CAST", "COALESCE", "IF", "BEGIN", "COMMIT", "ROLLBACK", "GRANT", "REVOKE", "TRUNCATE", "WITH", "RECURSIVE" }; private static readonly Regex SyntaxPattern = new Regex("(//[^\\n]*|#[^\\n]*)|(\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*')|(\\b\\d+\\.?\\d*[fFdDmMlL]?\\b)|(\\b[A-Z]\\w*(?=\\s*[\\.<\\(]))|(\\b\\w+(?=\\s*\\())|(\\b\\w+\\b)", RegexOptions.Compiled); public static bool EnableFilePathHighlight { get; set; } = true; public static StackPanel Render(string markdown, Brush textColor, Brush secondaryColor, Brush accentColor, Brush codeBg) { StackPanel stackPanel = new StackPanel(); if (string.IsNullOrEmpty(markdown)) { return stackPanel; } string[] array = markdown.Replace("\r\n", "\n").Split('\n'); int i = 0; while (i < array.Length) { string text = array[i]; if (text.TrimStart().StartsWith("```")) { object obj; if (text.TrimStart().Length <= 3) { obj = ""; } else { string text2 = text.TrimStart(); obj = text2.Substring(3, text2.Length - 3).Trim(); } string lang = (string)obj; StringBuilder stringBuilder = new StringBuilder(); for (i++; i < array.Length && !array[i].TrimStart().StartsWith("```"); i++) { stringBuilder.AppendLine(array[i]); } if (i < array.Length) { i++; } Border element = CreateCodeBlock(stringBuilder.ToString().TrimEnd(), lang, textColor, codeBg, accentColor); stackPanel.Children.Add(element); } else if (string.IsNullOrWhiteSpace(text)) { stackPanel.Children.Add(new Border { Height = 6.0 }); i++; } else if (Regex.IsMatch(text.Trim(), "^-{3,}$|^\\*{3,}$")) { stackPanel.Children.Add(new Border { Height = 1.0, Background = secondaryColor, Opacity = 0.3, Margin = new Thickness(0.0, 8.0, 0.0, 8.0) }); i++; } else if (text.StartsWith('#')) { int j; for (j = 0; j < text.Length && text[j] == '#'; j++) { } string text2 = text; int num = j; string text3 = text2.Substring(num, text2.Length - num).Trim(); if (1 == 0) { } double num2 = j switch { 1 => 20.0, 2 => 17.0, 3 => 15.0, _ => 14.0, }; if (1 == 0) { } double fontSize = num2; TextBlock textBlock = new TextBlock { FontSize = fontSize, FontWeight = FontWeights.Bold, Foreground = textColor, TextWrapping = TextWrapping.Wrap, Margin = new Thickness(0.0, (j == 1) ? 12 : 8, 0.0, 4.0) }; AddInlines(textBlock.Inlines, text3, textColor, accentColor, codeBg); stackPanel.Children.Add(textBlock); i++; } else if (Regex.IsMatch(text, "^\\s*[-*]\\s") || Regex.IsMatch(text, "^\\s*\\d+\\.\\s")) { Match match = Regex.Match(text, "^(\\s*)([-*]|\\d+\\.)\\s(.*)"); if (match.Success) { int num3 = match.Groups[1].Value.Length / 2; string value = match.Groups[2].Value; string value2 = match.Groups[3].Value; bool flag = ((value == "-" || value == "*") ? true : false); string text4 = (flag ? "•" : value); Grid grid = new Grid { Margin = new Thickness(12 + num3 * 16, 2.0, 0.0, 2.0) }; grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(18.0) }); grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0, GridUnitType.Star) }); TextBlock element2 = new TextBlock { Text = text4, FontSize = 13.5, Foreground = accentColor, VerticalAlignment = VerticalAlignment.Top }; Grid.SetColumn(element2, 0); grid.Children.Add(element2); TextBlock textBlock2 = new TextBlock { FontSize = 13.5, Foreground = textColor, TextWrapping = TextWrapping.Wrap, VerticalAlignment = VerticalAlignment.Top }; Grid.SetColumn(textBlock2, 1); AddInlines(textBlock2.Inlines, value2, textColor, accentColor, codeBg); grid.Children.Add(textBlock2); stackPanel.Children.Add(grid); } i++; } else if (text.TrimStart().StartsWith('>')) { List list = new List(); for (; i < array.Length && array[i].TrimStart().StartsWith('>'); i++) { string text5 = array[i].TrimStart(); object item; if (text5.Length <= 1) { item = ""; } else { string text2 = text5; item = text2.Substring(1, text2.Length - 1).TrimStart(); } list.Add((string)item); } Border border = new Border { BorderBrush = accentColor, BorderThickness = new Thickness(3.0, 0.0, 0.0, 0.0), Padding = new Thickness(12.0, 6.0, 8.0, 6.0), Margin = new Thickness(4.0, 4.0, 0.0, 4.0), Background = new SolidColorBrush(Color.FromArgb(16, byte.MaxValue, byte.MaxValue, byte.MaxValue)) }; TextBlock textBlock3 = new TextBlock { FontSize = 13.0, FontStyle = FontStyles.Italic, Foreground = secondaryColor, TextWrapping = TextWrapping.Wrap, LineHeight = 20.0 }; AddInlines(textBlock3.Inlines, string.Join("\n", list), textColor, accentColor, codeBg); border.Child = textBlock3; stackPanel.Children.Add(border); } else if (text.Contains('|') && text.Trim().StartsWith('|')) { List list2 = new List(); for (; i < array.Length && array[i].Contains('|'); i++) { list2.Add(array[i]); } FrameworkElement frameworkElement = CreateMarkdownTable(list2, textColor, accentColor, codeBg); if (frameworkElement != null) { stackPanel.Children.Add(frameworkElement); } } else { TextBlock textBlock4 = new TextBlock { FontSize = 13.5, Foreground = textColor, TextWrapping = TextWrapping.Wrap, LineHeight = 22.0, Margin = new Thickness(0.0, 2.0, 0.0, 2.0) }; AddInlines(textBlock4.Inlines, text, textColor, accentColor, codeBg); stackPanel.Children.Add(textBlock4); i++; } } return stackPanel; } private static void AddInlines(InlineCollection inlines, string text, Brush textColor, Brush accentColor, Brush codeBg) { string pattern = "(\\[([^\\]]+)\\]\\(([^)]+)\\)|~~(.+?)~~|\\*\\*(.+?)\\*\\*|\\*(.+?)\\*|`(.+?)`|([^*`~\\[]+))"; MatchCollection matchCollection = Regex.Matches(text, pattern); foreach (Match item in matchCollection) { if (item.Groups[2].Success && item.Groups[3].Success) { string linkUrl = item.Groups[3].Value; Hyperlink hyperlink = new Hyperlink(new Run(item.Groups[2].Value)) { Foreground = accentColor, TextDecorations = null, Cursor = Cursors.Hand }; hyperlink.Click += delegate { try { Process.Start(new ProcessStartInfo(linkUrl) { UseShellExecute = true }); } catch { } }; inlines.Add(hyperlink); } else if (item.Groups[4].Success) { inlines.Add(new Run(item.Groups[4].Value) { TextDecorations = TextDecorations.Strikethrough, Foreground = new SolidColorBrush(Color.FromArgb(153, byte.MaxValue, byte.MaxValue, byte.MaxValue)) }); } else if (item.Groups[5].Success) { inlines.Add(new Run(item.Groups[5].Value) { FontWeight = FontWeights.Bold }); } else if (item.Groups[6].Success) { inlines.Add(new Run(item.Groups[6].Value) { FontStyle = FontStyles.Italic }); } else if (item.Groups[7].Success) { Border childUIElement = new Border { Background = codeBg, CornerRadius = new CornerRadius(4.0), Padding = new Thickness(5.0, 1.0, 5.0, 1.0), Margin = new Thickness(1.0, 0.0, 1.0, 0.0), Child = new TextBlock { Text = item.Groups[7].Value, FontFamily = new FontFamily("Cascadia Code, Consolas, monospace"), FontSize = 12.5, Foreground = accentColor } }; inlines.Add(new InlineUIContainer(childUIElement) { BaselineAlignment = BaselineAlignment.Center }); } else if (item.Groups[8].Success) { AddPlainTextWithFilePaths(inlines, item.Groups[8].Value); } } } private static void AddPlainTextWithFilePaths(InlineCollection inlines, string text) { if (!EnableFilePathHighlight) { inlines.Add(new Run(text)); return; } MatchCollection matchCollection = FilePathPattern.Matches(text); if (matchCollection.Count == 0) { inlines.Add(new Run(text)); return; } int num = 0; foreach (Match item in matchCollection) { if (item.Index > num) { int num2 = num; inlines.Add(new Run(text.Substring(num2, item.Index - num2))); } inlines.Add(new Run(item.Value) { Foreground = new SolidColorBrush(Color.FromRgb(59, 130, 246)), FontWeight = FontWeights.Medium }); num = item.Index + item.Length; } if (num < text.Length) { int num2 = num; inlines.Add(new Run(text.Substring(num2, text.Length - num2))); } } private static FrameworkElement? CreateMarkdownTable(List rows, Brush textColor, Brush accentColor, Brush codeBg) { if (rows.Count < 2) { return null; } string[] array = ParseRow(rows[0]); int num = array.Length; if (num == 0) { return null; } int num2 = 1; if (rows.Count > 1 && Regex.IsMatch(rows[1].Trim(), "^[\\|\\s:\\-]+$")) { num2 = 2; } Grid grid = new Grid { Margin = new Thickness(0.0, 6.0, 0.0, 6.0) }; for (int i = 0; i < num; i++) { grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0, GridUnitType.Star) }); } int num3 = 0; grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); for (int j = 0; j < num; j++) { Border border = new Border { Background = new SolidColorBrush(Color.FromArgb(32, byte.MaxValue, byte.MaxValue, byte.MaxValue)), BorderBrush = new SolidColorBrush(Color.FromArgb(48, byte.MaxValue, byte.MaxValue, byte.MaxValue)), BorderThickness = new Thickness(0.0, 0.0, (j < num - 1) ? 1 : 0, 1.0), Padding = new Thickness(8.0, 5.0, 8.0, 5.0) }; TextBlock child = new TextBlock { Text = ((j < array.Length) ? array[j] : ""), FontSize = 12.0, FontWeight = FontWeights.SemiBold, Foreground = textColor, TextWrapping = TextWrapping.Wrap }; border.Child = child; Grid.SetRow(border, num3); Grid.SetColumn(border, j); grid.Children.Add(border); } num3++; for (int k = num2; k < rows.Count; k++) { string[] array2 = ParseRow(rows[k]); grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); for (int l = 0; l < num; l++) { Border border2 = new Border { Background = ((k % 2 == 0) ? new SolidColorBrush(Color.FromArgb(8, byte.MaxValue, byte.MaxValue, byte.MaxValue)) : Brushes.Transparent), BorderBrush = new SolidColorBrush(Color.FromArgb(24, byte.MaxValue, byte.MaxValue, byte.MaxValue)), BorderThickness = new Thickness(0.0, 0.0, (l < num - 1) ? 1 : 0, 1.0), Padding = new Thickness(8.0, 4.0, 8.0, 4.0) }; TextBlock textBlock = new TextBlock { FontSize = 12.0, Foreground = textColor, TextWrapping = TextWrapping.Wrap }; AddInlines(textBlock.Inlines, (l < array2.Length) ? array2[l] : "", textColor, accentColor, codeBg); border2.Child = textBlock; Grid.SetRow(border2, num3); Grid.SetColumn(border2, l); grid.Children.Add(border2); } num3++; } Border border3 = new Border { CornerRadius = new CornerRadius(6.0), BorderBrush = new SolidColorBrush(Color.FromArgb(48, byte.MaxValue, byte.MaxValue, byte.MaxValue)), BorderThickness = new Thickness(1.0), ClipToBounds = true, Margin = new Thickness(0.0, 4.0, 0.0, 4.0) }; border3.Child = grid; return border3; static string[] ParseRow(string row) { string text = row.Trim().Trim('|'); return (from c in text.Split('|') select c.Trim()).ToArray(); } } private static Border CreateCodeBlock(string code, string lang, Brush textColor, Brush codeBg, Brush accentColor) { Border border = new Border { Background = codeBg, CornerRadius = new CornerRadius(10.0), Margin = new Thickness(0.0, 6.0, 0.0, 6.0), Padding = new Thickness(0.0) }; StackPanel stackPanel = new StackPanel(); Border border2 = new Border { Background = new SolidColorBrush(Color.FromArgb(30, byte.MaxValue, byte.MaxValue, byte.MaxValue)), CornerRadius = new CornerRadius(10.0, 10.0, 0.0, 0.0), Padding = new Thickness(14.0, 6.0, 8.0, 6.0) }; Grid grid = new Grid(); grid.Children.Add(new TextBlock { Text = (string.IsNullOrEmpty(lang) ? "code" : lang), FontSize = 11.0, Foreground = accentColor, FontWeight = FontWeights.SemiBold, VerticalAlignment = VerticalAlignment.Center }); StackPanel stackPanel2 = new StackPanel { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Center }; string capturedCode = code; string capturedLang = lang; Button button = CreateCodeHeaderButton("\ue74e", "저장", textColor); button.Click += delegate { try { string extensionForLang = GetExtensionForLang(capturedLang); SaveFileDialog saveFileDialog = new SaveFileDialog { FileName = "code" + extensionForLang, Filter = $"코드 파일 (*{extensionForLang})|*{extensionForLang}|모든 파일 (*.*)|*.*" }; if (saveFileDialog.ShowDialog() == true) { File.WriteAllText(saveFileDialog.FileName, capturedCode); } } catch { } }; stackPanel2.Children.Add(button); Button button2 = CreateCodeHeaderButton("\ue740", "확대", textColor); button2.Click += delegate { ShowCodeFullScreen(capturedCode, capturedLang, codeBg, textColor); }; stackPanel2.Children.Add(button2); Button button3 = CreateCodeHeaderButton("\ue8c8", "복사", textColor); button3.Click += delegate { try { Clipboard.SetText(capturedCode); } catch { } }; stackPanel2.Children.Add(button3); grid.Children.Add(stackPanel2); border2.Child = grid; stackPanel.Children.Add(border2); Grid grid2 = new Grid { Margin = new Thickness(0.0, 0.0, 0.0, 4.0) }; grid2.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); grid2.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0, GridUnitType.Star) }); string[] array = code.Split('\n'); TextBlock element = new TextBlock { FontFamily = new FontFamily("Cascadia Code, Consolas, monospace"), FontSize = 12.5, Foreground = new SolidColorBrush(Color.FromArgb(80, byte.MaxValue, byte.MaxValue, byte.MaxValue)), Padding = new Thickness(10.0, 10.0, 6.0, 14.0), LineHeight = 20.0, TextAlignment = TextAlignment.Right, Text = string.Join("\n", Enumerable.Range(1, array.Length)) }; Grid.SetColumn(element, 0); grid2.Children.Add(element); TextBlock textBlock = new TextBlock { FontFamily = new FontFamily("Cascadia Code, Consolas, monospace"), FontSize = 12.5, Foreground = textColor, TextWrapping = TextWrapping.Wrap, Padding = new Thickness(8.0, 10.0, 14.0, 14.0), LineHeight = 20.0 }; ApplySyntaxHighlighting(textBlock, code, lang, textColor); Grid.SetColumn(textBlock, 1); grid2.Children.Add(textBlock); stackPanel.Children.Add(grid2); border.Child = stackPanel; return border; } private static Button CreateCodeHeaderButton(string mdlIcon, string label, Brush fg) { return new Button { Background = Brushes.Transparent, BorderThickness = new Thickness(0.0), Cursor = Cursors.Hand, VerticalAlignment = VerticalAlignment.Center, Padding = new Thickness(5.0, 2.0, 5.0, 2.0), Margin = new Thickness(2.0, 0.0, 0.0, 0.0), Content = new StackPanel { Orientation = Orientation.Horizontal, Children = { (UIElement)new TextBlock { Text = mdlIcon, FontFamily = new FontFamily("Segoe MDL2 Assets"), FontSize = 10.0, Foreground = fg, Opacity = 0.6, VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(0.0, 0.0, 3.0, 0.0) }, (UIElement)new TextBlock { Text = label, FontSize = 10.0, Foreground = fg, Opacity = 0.6 } } } }; } private static string GetExtensionForLang(string lang) { string text = (lang ?? "").ToLowerInvariant(); if (1 == 0) { } string result; switch (text) { case "csharp": case "cs": result = ".cs"; break; case "python": case "py": result = ".py"; break; case "javascript": case "js": result = ".js"; break; case "typescript": case "ts": result = ".ts"; break; case "java": result = ".java"; break; case "html": result = ".html"; break; case "css": result = ".css"; break; case "json": result = ".json"; break; case "xml": result = ".xml"; break; case "sql": result = ".sql"; break; case "bash": case "sh": case "shell": result = ".sh"; break; case "powershell": case "ps1": result = ".ps1"; break; case "bat": case "cmd": result = ".bat"; break; case "yaml": case "yml": result = ".yml"; break; case "markdown": case "md": result = ".md"; break; case "cpp": case "c++": result = ".cpp"; break; case "c": result = ".c"; break; case "go": result = ".go"; break; case "rust": case "rs": result = ".rs"; break; default: result = ".txt"; break; } if (1 == 0) { } return result; } private static void ShowCodeFullScreen(string code, string lang, Brush codeBg, Brush textColor) { Window window = new Window(); window.Title = "코드 — " + (string.IsNullOrEmpty(lang) ? "code" : lang); window.Width = 900.0; window.Height = 650.0; window.WindowStartupLocation = WindowStartupLocation.CenterScreen; window.Background = ((codeBg is SolidColorBrush solidColorBrush) ? new SolidColorBrush(solidColorBrush.Color) : Brushes.Black); Window window2 = window; Grid grid = new Grid(); grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0, GridUnitType.Star) }); string[] array = code.Split('\n'); TextBlock element = new TextBlock { FontFamily = new FontFamily("Cascadia Code, Consolas, monospace"), FontSize = 13.0, LineHeight = 22.0, Foreground = new SolidColorBrush(Color.FromArgb(80, byte.MaxValue, byte.MaxValue, byte.MaxValue)), Padding = new Thickness(16.0, 16.0, 8.0, 16.0), TextAlignment = TextAlignment.Right, Text = string.Join("\n", Enumerable.Range(1, array.Length)) }; Grid.SetColumn(element, 0); grid.Children.Add(element); TextBlock textBlock = new TextBlock { FontFamily = new FontFamily("Cascadia Code, Consolas, monospace"), FontSize = 13.0, LineHeight = 22.0, Foreground = textColor, TextWrapping = TextWrapping.Wrap, Padding = new Thickness(8.0, 16.0, 16.0, 16.0) }; ApplySyntaxHighlighting(textBlock, code, lang, textColor); Grid.SetColumn(textBlock, 1); grid.Children.Add(textBlock); ScrollViewer content = new ScrollViewer { VerticalScrollBarVisibility = ScrollBarVisibility.Auto, HorizontalScrollBarVisibility = ScrollBarVisibility.Auto, Content = grid }; window2.Content = content; window2.Show(); } private static HashSet GetKeywordsForLang(string lang) { string text = lang.ToLowerInvariant(); if (1 == 0) { } HashSet result; switch (text) { case "csharp": case "cs": case "c#": result = CSharpKeywords; break; case "python": case "py": result = PythonKeywords; break; case "javascript": case "js": case "jsx": result = JsKeywords; break; case "typescript": case "ts": case "tsx": result = JsKeywords; break; case "java": case "kotlin": case "kt": result = JavaKeywords; break; case "sql": case "mysql": case "postgresql": case "sqlite": result = SqlKeywords; break; case "go": case "golang": result = new HashSet(StringComparer.Ordinal) { "break", "case", "chan", "const", "continue", "default", "defer", "else", "fallthrough", "for", "func", "go", "goto", "if", "import", "interface", "map", "package", "range", "return", "select", "struct", "switch", "type", "var", "nil", "true", "false", "append", "len", "cap", "make", "new", "panic", "recover" }; break; case "rust": case "rs": result = new HashSet(StringComparer.Ordinal) { "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", "while", "yield", "Box", "Vec", "String", "Option", "Result", "Some", "None", "Ok", "Err", "println", "macro_rules" }; break; case "cpp": case "c++": case "c": case "h": case "hpp": result = new HashSet(StringComparer.Ordinal) { "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "class", "namespace", "using", "public", "private", "protected", "virtual", "override", "template", "typename", "nullptr", "true", "false", "new", "delete", "throw", "try", "catch", "const_cast", "dynamic_cast", "static_cast", "reinterpret_cast", "bool", "string", "include", "define", "ifdef", "ifndef", "endif" }; break; default: result = CSharpKeywords; break; } if (1 == 0) { } return result; } private static void ApplySyntaxHighlighting(TextBlock tb, string code, string lang, Brush defaultColor) { if (string.IsNullOrEmpty(lang) || string.IsNullOrEmpty(code)) { tb.Text = code; return; } HashSet keywordsForLang = GetKeywordsForLang(lang); bool flag; switch (lang.ToLowerInvariant()) { case "python": case "py": case "bash": case "sh": case "shell": case "ruby": case "rb": case "yaml": case "yml": case "toml": case "powershell": case "ps1": flag = true; break; default: flag = false; break; } bool flag2 = flag; foreach (Match item in SyntaxPattern.Matches(code)) { if (item.Groups[1].Success) { string value = item.Groups[1].Value; if (value.StartsWith('#') && !flag2) { tb.Inlines.Add(new Run(value) { Foreground = defaultColor }); } else { tb.Inlines.Add(new Run(value) { Foreground = CommentBrush, FontStyle = FontStyles.Italic }); } } else if (item.Groups[2].Success) { tb.Inlines.Add(new Run(item.Groups[2].Value) { Foreground = StringBrush }); } else if (item.Groups[3].Success) { tb.Inlines.Add(new Run(item.Groups[3].Value) { Foreground = NumberBrush }); } else if (item.Groups[4].Success) { string value2 = item.Groups[4].Value; tb.Inlines.Add(new Run(value2) { Foreground = (keywordsForLang.Contains(value2) ? KeywordBrush : TypeBrush) }); } else if (item.Groups[5].Success) { string value3 = item.Groups[5].Value; if (keywordsForLang.Contains(value3)) { tb.Inlines.Add(new Run(value3) { Foreground = KeywordBrush }); } else { tb.Inlines.Add(new Run(value3) { Foreground = MethodBrush }); } } else if (item.Groups[6].Success) { string value4 = item.Groups[6].Value; if (keywordsForLang.Contains(value4)) { tb.Inlines.Add(new Run(value4) { Foreground = KeywordBrush }); } else { tb.Inlines.Add(new Run(value4) { Foreground = defaultColor }); } } } tb.Inlines.Clear(); int num = 0; foreach (Match item2 in SyntaxPattern.Matches(code)) { if (item2.Index > num) { InlineCollection inlines = tb.Inlines; int num2 = num; inlines.Add(new Run(code.Substring(num2, item2.Index - num2)) { Foreground = defaultColor }); } if (item2.Groups[1].Success) { string value5 = item2.Groups[1].Value; if (value5.StartsWith('#') && !flag2) { tb.Inlines.Add(new Run(value5) { Foreground = defaultColor }); } else { tb.Inlines.Add(new Run(value5) { Foreground = CommentBrush, FontStyle = FontStyles.Italic }); } } else if (item2.Groups[2].Success) { tb.Inlines.Add(new Run(item2.Groups[2].Value) { Foreground = StringBrush }); } else if (item2.Groups[3].Success) { tb.Inlines.Add(new Run(item2.Groups[3].Value) { Foreground = NumberBrush }); } else if (item2.Groups[4].Success) { string value6 = item2.Groups[4].Value; tb.Inlines.Add(new Run(value6) { Foreground = (keywordsForLang.Contains(value6) ? KeywordBrush : TypeBrush) }); } else if (item2.Groups[5].Success) { string value7 = item2.Groups[5].Value; tb.Inlines.Add(new Run(value7) { Foreground = (keywordsForLang.Contains(value7) ? KeywordBrush : MethodBrush) }); } else if (item2.Groups[6].Success) { string value8 = item2.Groups[6].Value; tb.Inlines.Add(new Run(value8) { Foreground = (keywordsForLang.Contains(value8) ? KeywordBrush : defaultColor) }); } num = item2.Index + item2.Length; } if (num < code.Length) { InlineCollection inlines2 = tb.Inlines; int num2 = num; inlines2.Add(new Run(code.Substring(num2, code.Length - num2)) { Foreground = defaultColor }); } } }