Files

1092 lines
30 KiB
C#

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<string> CSharpKeywords = new HashSet<string>(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<string> PythonKeywords = new HashSet<string>(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<string> JsKeywords = new HashSet<string>(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<string> JavaKeywords = new HashSet<string>(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<string> SqlKeywords = new HashSet<string>(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<string> list = new List<string>();
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<string> list2 = new List<string>();
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<string> 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<string> GetKeywordsForLang(string lang)
{
string text = lang.ToLowerInvariant();
if (1 == 0)
{
}
HashSet<string> 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<string>(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<string>(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<string>(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<string> 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
});
}
}
}