using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Folding;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using TeamAAS_VP.Core;
using TeamAAS_VP.Models;
using TeamAAS_VP.ViewModels.DebugMod;
using Prism.Commands;
using TeamAAS_VP;
using TeamAAS_VP.Resources.Languages;
namespace TeamAAS_VP.Controls
{
///
/// ScriptEditControl.xaml 的交互逻辑
///
public partial class ScriptEditControl : UserControl
{
///
/// 当前app的所有程序集中的类
///
Dictionary ClassMemberlist = new Dictionary();
#region 属性
private double _fontSize = 14;
public new double FontSize
{
get { return _fontSize; }
set { _fontSize = value;
this.textEditor.FontSize = value;
}
}
private TextDocument _document = new TextDocument();
public TextDocument Document
{
get { return _document; }
set { _document = value;
}
}
private TextArea _mTextArea;
public TextArea mTextArea
{
get { return _mTextArea; }
set { _mTextArea = value; }
}
private ObservableCollection _CompileMessageList = new ObservableCollection();
public ObservableCollection CompileMessageList
{
get { return _CompileMessageList; }
set {
_CompileMessageList = value;
this.messagelist.ItemsSource = value;
}
}
private bool _IsCompile = true;
public bool IsCompile
{
get { return _IsCompile; }
set { _IsCompile = value;
this.Dispatcher.Invoke(new Action(() => {
this.btn1.IsEnabled = value;
this.btn2.IsEnabled = value;
this.btn3.IsEnabled = value;
this.btn4.IsEnabled = value;
this.btn5.IsEnabled = value;
this.btn6.IsEnabled = value;
this.btn7.IsEnabled = value;
this.btn8.IsEnabled = value;
this.btn9.IsEnabled = value;
this.btn10.IsEnabled = value;
this.btn11.IsEnabled = value;
this.btn12.IsEnabled = value;
this.btnShowEndOfLine.IsEnabled= value;
this.btnShowLineNumbers.IsEnabled= value;
this.btnWordWrap.IsEnabled= value;
this.textEditor.IsEnabled= value;
}));
}
}
[Bindable(true)]
[Category("Common")]
[DefaultValue("")]
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value);
}
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ScriptEditControl), new PropertyMetadata(default(string),new PropertyChangedCallback(OnValueChanged)));
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ScriptEditControl control)
{
if (e.NewValue!=e.OldValue)
{
if (!control.isWrite)
{
control.textEditor.Document.Text = (string)e.NewValue;
}
}
}
}
[Bindable(true)]
[Category("Common")]
[DefaultValue("")]
public string ScriptPath
{
get { return (string)GetValue(ScriptPathProperty); }
set { SetValue(ScriptPathProperty, value); }
}
// Using a DependencyProperty as the backing store for ScriptPath. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScriptPathProperty =
DependencyProperty.Register("ScriptPath", typeof(string), typeof(ScriptEditControl), new PropertyMetadata(default(string), new PropertyChangedCallback(OnPathChanged)));
private static void OnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ScriptEditControl control)
{
if (e.NewValue != e.OldValue)
{
}
}
}
[Bindable(true)]
[Category("Common")]
[DefaultValue("")]
public string CompileType
{
get { return (string)GetValue(CompileTypeProperty); }
set { SetValue(CompileTypeProperty, value); }
}
// Using a DependencyProperty as the backing store for CompileType. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CompileTypeProperty =
DependencyProperty.Register("CompileType", typeof(string), typeof(ScriptEditControl), new PropertyMetadata(default(string)));
#endregion
#region 命令
#endregion
#region 事件
public static readonly RoutedEvent SaveScriptEvent=EventManager.RegisterRoutedEvent("OnSaveScript", RoutingStrategy.Bubble,typeof(RoutedEventHandler),typeof(ScriptEditControl));
public event RoutedEventHandler OnSaveScript
{
add { AddHandler(SaveScriptEvent, value);}
remove { RemoveHandler(SaveScriptEvent, value);}
}
#endregion
public ScriptEditControl()
{
InitializeComponent();
this.Loaded += ScriptEditControl_Loaded;
this.textEditor.PreviewMouseWheel += TextEditor_PreviewMouseWheel;
this.messagelist.SelectionChanged += Messagelist_SelectionChanged;
this.textEditor.Document = Document;
this.textEditor.Document.TextChanged += Document_TextChanged;
this.messagelist.ItemsSource= new ObservableCollection();
}
bool isWrite = false;
private void Document_TextChanged(object sender, EventArgs e)
{
isWrite = true;
Text = this.textEditor.Document.Text;
isWrite = false;
}
#region 方法
bool isFirst=true;
private async void ScriptEditControl_Loaded(object sender, RoutedEventArgs e)
{
if (isFirst)
{
textEditor.Options.HighlightCurrentLine = true;
mTextArea = textEditor.TextArea;
textEditor.TextArea.TextEntering += TextArea_TextEntering;
textEditor.TextArea.TextEntered += TextArea_TextEntered;
//textEditor.PreviewMouseWheel += vm.TextEditor_PreviewMouseWheel;
ICSharpCode.AvalonEdit.Search.SearchPanel.Install(textEditor);
foldingManager = FoldingManager.Install(textEditor.TextArea);
foldingStrategy = new BraceFoldingStrategy();
DispatcherTimer foldingUpdateTimer = new DispatcherTimer();
foldingUpdateTimer.Interval = TimeSpan.FromSeconds(2);
foldingUpdateTimer.Tick += delegate { UpdateFoldings(); };
foldingUpdateTimer.Start();
await Task.Run(() =>
{
try
{
var cc = GetTypesInNamespace(Assembly.GetExecutingAssembly(), "TeamAAS_VP");
foreach (var item in GetTypesInNamespace(Assembly.GetExecutingAssembly(), "TeamAAS_VP"))
{
if (!item.IsPublic)
{
continue;
}
ClassMemberlist.Add(item.Name, item);
}
//获取当前应用域中加载的所有程序集数组
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var item in assemblies)
{
try
{
foreach (var item1 in GetTypesInNamespace(Assembly.Load(item.FullName)))
{
if (!item1.IsPublic)
{
continue;
}
ClassMemberlist.Add(item1.Name, item1);
}
}
catch (Exception)
{
}
}
}
catch (Exception)
{
}
});
isFirst = false;
}
}
///
/// 打开脚本文件
///
///
///
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = Lang.打开脚本;
dlg.Filter = $"{Lang.脚本文件}|*.cs|{Lang.所有文件}.*|*.*";
dlg.CheckFileExists = true;
if (dlg.ShowDialog() ?? false)
{
this.textEditor.Document.Text = FileHelper.ReadFile(dlg.FileName);
}
}
catch (Exception)
{
}
}
///
/// 保存脚本
///
///
///
private void Button_Click_1(object sender, RoutedEventArgs e)
{
try
{
if (string.IsNullOrEmpty(ScriptPath))
{
return;
}
FileHelper.WriteFile(this.textEditor.Document.Text, ScriptPath);
RoutedEventArgs args = new RoutedEventArgs(ScriptEditControl.SaveScriptEvent, Text);
RaiseEvent(args);
MessageBox.Show("Succed!");
}
catch (Exception ex)
{
LogHelper.WriteLogError(Lang.保存脚本文件时出错,ex);
MessageBox.Show(ex.Message);
}
}
///
/// 另存为
///
///
///
private void Button_Click_2(object sender, RoutedEventArgs e)
{
try
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Title = $"{Lang.保存脚本}";
dlg.DefaultExt = ".cs";
dlg.Filter = $"C# {Lang.文件} (*.cs)|*.cs|{Lang.所有文件} (*.txt)|*.txt|All files (*.*)|*.*";
if (dlg.ShowDialog() ?? false)
{
FileHelper.WriteFile(this.textEditor.Document.Text, dlg.FileName);
}
}
catch (Exception)
{
}
}
///
/// 字体放大
///
///
///
private void Button_Click_3(object sender, RoutedEventArgs e)
{
if (FontSize < 50)
{
FontSize += 1;
}
}
///
/// 字体缩小
///
///
///
private void Button_Click_4(object sender, RoutedEventArgs e)
{
if (FontSize > 1)
FontSize -= 1;
}
///
/// 编译
///
///
///
private async void Button_Click_5(object sender, RoutedEventArgs e)
{
IsCompile = false;
CompileMessageList.Clear();
this.messagelist.ItemsSource = CompileMessageList;
CompileMessageList.Add(new ScriptCompileMessage() { DT = DateTime.Now, Kind = MaterialDesignThemes.Wpf.PackIconKind.InformationSlabCircleOutline, FontColol = new SolidColorBrush(Colors.Black), Message = Lang.开始编译});
if (!string.IsNullOrEmpty(CompileType) && CompileType== "VisionScripting")
{
var rst = await ScriptHelper.CompileVisionScriptingAsync(this.textEditor.Document.Text,null,null,null,null,null,null);
if (rst.Item1)
{
CompileMessageList.Add(new ScriptCompileMessage() { DT = DateTime.Now, Kind = MaterialDesignThemes.Wpf.PackIconKind.CheckCircle, FontColol = new SolidColorBrush(Colors.Green), Message = Lang.编译完成 });
//rst.Item3.Invoke(rst.Item4,null);
}
else
{
foreach (var item in rst.Item2)
{
CompileMessageList.Add(new ScriptCompileMessage() { DT = DateTime.Now, Kind = MaterialDesignThemes.Wpf.PackIconKind.CloseCircle, FontColol = new SolidColorBrush(Colors.Red), Message = item });
}
}
}
else
{
var rst = await ScriptHelper.CompileAsync(this.textEditor.Document.Text, null, null, null);
if (rst.Item1)
{
CompileMessageList.Add(new ScriptCompileMessage() { DT = DateTime.Now, Kind = MaterialDesignThemes.Wpf.PackIconKind.CheckCircle, FontColol = new SolidColorBrush(Colors.Green), Message = Lang.编译完成 });
//rst.Item3.Invoke(rst.Item4,null);
}
else
{
foreach (var item in rst.Item2)
{
CompileMessageList.Add(new ScriptCompileMessage() { DT = DateTime.Now, Kind = MaterialDesignThemes.Wpf.PackIconKind.CloseCircle, FontColol = new SolidColorBrush(Colors.Red), Message = item });
}
}
}
this.messagelist.ItemsSource = CompileMessageList;
IsCompile = true;
}
CompletionWindow completionWindow;
public void TextArea_TextEntered(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
if (e.Text == ".")
{
//1.获取.前面的字符串
// 获取当前光标位置
int caretOffset = mTextArea.Caret.Offset;
// 获取当前光标位置前面的单词(以空格、标点等作为分隔符)
TextDocument document = Document;
int startOffset = Math.Max(0, caretOffset - 1); // 从当前位置的前一个字符开始
// 找到单词的起始位置
while (startOffset >= 0 && !char.IsWhiteSpace(document.GetCharAt(startOffset)))
{
startOffset--;
}
startOffset++; // 回到单词的起始位置
// 获取单词的文本
int endOffset = caretOffset - 1;
// 使用 AvalonEdit 提供的 TextUtilities 获取当前位置前面的单词
string word = document.GetText(startOffset, endOffset - startOffset);
//2.检索字符串,并得到对象
var type = word.GetType();
foreach (var item in ClassMemberlist)
{
if (item.Key.ToLower().Trim(' ') == word.ToLower().Trim(' '))
{
type = item.Value;
break;
}
}
if (type == null)
return;
//3.检索对象中所有的属性,字段,事件,方法,并做提示
// open code completion after the user has pressed dot:
completionWindow = new CompletionWindow(((ICSharpCode.AvalonEdit.Editing.TextArea)sender));
// provide AvalonEdit with the data:
IList data = completionWindow.CompletionList.CompletionData;
System.Reflection.MethodInfo[] methodInfos = type.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static);
System.Reflection.PropertyInfo[] propertyInfos = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static); // System.Reflection.BindingFlags.Public| System.Reflection.BindingFlags.Static
System.Reflection.EventInfo[] eventInfos = type.GetEvents(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static);
System.Reflection.FieldInfo[] fieldInfos = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static);
List proposals = new List();
//遍历字段
foreach (var item in fieldInfos)
{
data.Add(new ScriptCompletionData(item.Name, CoreMemberType.Field));
}
//遍历属性
foreach (var item in propertyInfos)
{
data.Add(new ScriptCompletionData(item.Name, CoreMemberType.Property));
}
//遍历方法
foreach (var item in methodInfos)
{
if (item.IsSpecialName)
{
continue;
}
if (item.ToString().Split(' ').Length >= 2)
{
data.Add(new ScriptCompletionData(item.ToString().Split(" ".ToCharArray(), 2)[1].Replace(" ", ""), CoreMemberType.Void));
}
else
{
data.Add(new ScriptCompletionData(item.Name, CoreMemberType.Void));
}
}
//遍历事件
foreach (var item in eventInfos)
{
data.Add(new ScriptCompletionData(item.Name, CoreMemberType.Event));
}
completionWindow.Show();
completionWindow.Closed += delegate {
completionWindow = null;
};
}
else if (e.Text == "(")
{
Document.Insert(mTextArea.Caret.Offset, ")");
mTextArea.Caret.Offset = mTextArea.Caret.Offset - 1;
}
else if (e.Text == "{")
{
Document.Insert(mTextArea.Caret.Offset, "}");
mTextArea.Caret.Offset = mTextArea.Caret.Offset - 1;
}
}
public void TextArea_TextEntering(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
if (e.Text.Length > 0 && completionWindow != null)
{
if (!char.IsLetterOrDigit(e.Text[0]))
{
// Whenever a non-letter is typed while the completion window is open,
// insert the currently selected element.
completionWindow.CompletionList.RequestInsertion(e);
}
}
// do not set e.Handled=true - we still want to insert the character that was typed
}
///
/// 获取指定命名空间下的所有类
///
///
///
///
private Type[] GetTypesInNamespace(Assembly assembly, string nameSpace = null)
{
if (nameSpace == null)
{
return assembly.GetTypes();
}
else
{
return assembly.GetTypes();
//return assembly.GetTypes().Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal)).ToArray();
}
}
public void TextEditor_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
// 检查是否按下了 Ctrl 键
if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
// 根据鼠标滚轮方向调整字体大小
if (e.Delta > 0)
{
Button_Click_3(null,null);
}
else
{
Button_Click_4(null,null);
}
// 禁止事件继续传播,防止影响文本编辑器的滚动
e.Handled = true;
}
}
///
/// 编辑输出信息选中时
///
///
///
private void Messagelist_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView listView = sender as ListView;
ScriptCompileMessage item = listView.SelectedItem as ScriptCompileMessage;
if (item == null)
{
return;
}
if (item.Kind != MaterialDesignThemes.Wpf.PackIconKind.CloseCircle)
{
return;
}
// 正则表达式
string pattern = @"