using System.Reflection; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using Autodesk.Revit.UI; using AvalonDock; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Utils; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Text; using TextDocument = ICSharpCode.AvalonEdit.Document.TextDocument; namespace Szmedi.AIScriptRunner.RvScript { /// /// 每个脚本文件视图的ViewModel /// public partial class DocumentViewModel : ObservableObject /*ObservableRecipient, IRecipient*/ { [ObservableProperty] private bool _isReadOnly; RoslynEditorViewModel RoslynEditorViewModel { get; } public DocumentViewModel(RoslynEditorViewModel roslynEditorViewModel, string FilePath) { RoslynEditorViewModel = roslynEditorViewModel; this.FilePath = FilePath; Title = FileName; } // ... public DocumentViewModel(RoslynEditorViewModel roslynEditorViewModel) { //WeakReferenceMessenger.Default.Register(this, "RunScript", (r, m) => r.Receive(m)); RoslynEditorViewModel = roslynEditorViewModel; IsDirty = true; Title = FileName; } internal void Initialize(DocumentId id) { Id = id; if (Document != null && Document.TextLength > 0) { var doc = RoslynEditorViewModel.Host.GetDocument(id); if (doc != null) { RoslynEditorViewModel.Host.UpdateDocument(doc.WithText(SourceText.From(Document.Text))); IsDirty = false; } } } internal void OnTextChanged(object sender, EventArgs e) { IsDirty = true; } public DocumentId Id { get; private set; } [ObservableProperty] private TextDocument _document = null; [ObservableProperty] private string title = null; [ObservableProperty] [NotifyPropertyChangedFor(nameof(FileName))] [NotifyPropertyChangedFor(nameof(Title))] private bool isDirty = false; private string _isReadOnlyReason = string.Empty; public string IsReadOnlyReason { get { return _isReadOnlyReason; } protected set { SetProperty(ref _isReadOnlyReason, value); } } private string _filePath = null; public string FilePath { get { return _filePath; } set { if (_filePath != value) { _filePath = value; OnPropertyChanged(nameof(FilePath)); OnPropertyChanged(nameof(FileName)); OnPropertyChanged(nameof(Title)); if (File.Exists(_filePath)) { Document = new TextDocument(); IsDirty = false; IsReadOnly = false; // Check file attributes and set to read-only if file attributes indicate that if ((File.GetAttributes(_filePath) & FileAttributes.ReadOnly) != 0) { IsReadOnly = true; IsReadOnlyReason = "无法编辑该文件,另一个进程正在写入\n" + "如果你想编辑它,请修改访问许可或另存文件到其他位置。"; } using (FileStream fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (StreamReader reader = FileReader.OpenStream(fs, System.Text.Encoding.UTF8)) { Document = new TextDocument(reader.ReadToEnd()); } } ContentId = _filePath; } } } } public string FileName { get { if (FilePath == null) return "未命名脚本" + (IsDirty ? "*" : ""); return Path.GetFileName(FilePath) + (IsDirty ? "*" : ""); } } [ObservableProperty] private string _contentId = null; [ObservableProperty] private bool _isActive = false; [ObservableProperty] private bool _isSelected = false; public string Text { get; set; } public bool HasError { get; private set; } //private static MethodInfo HasSubmissionResult { get; } = // typeof(Compilation).GetMethod(nameof(HasSubmissionResult), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); [RelayCommand(CanExecute = nameof(IsDirty))] private void Save() { Text = GetCode(); RoslynEditorViewModel.Save(this, false); } private string GetCode() { var document = RoslynEditorViewModel.Host.GetDocument(Id); if (document == null) return string.Empty; return document.GetTextAsync()?.Result.ToString(); } [RelayCommand(CanExecute = nameof(IsDirty))] private void SaveAs() { Text = GetCode(); RoslynEditorViewModel.Save(this, true); } [RelayCommand] private void Close() { RoslynEditorViewModel.Close(this); } [RelayCommand] private void Run() { Text = GetCode(); RoslynEditorViewModel.Run(this); } [RelayCommand] private void Format() { var document = RoslynEditorViewModel.Host.GetDocument(Id); var formattedDocument = Formatter.FormatAsync(document).Result; RoslynEditorViewModel.Host.UpdateDocument(formattedDocument); } [RelayCommand] private void Comment() { if (RoslynEditorViewModel.CodeEditor == null) { return; } var roslynEditor = RoslynEditorViewModel.CodeEditor; var document = roslynEditor.Document; var startLine = document.GetLineByOffset(roslynEditor.SelectionStart); var endLine = document.GetLineByOffset(roslynEditor.SelectionStart + roslynEditor.SelectionLength); document.BeginUpdate(); var line = startLine; while (line != null && line.LineNumber <= endLine.LineNumber) { var whitespace = TextUtilities.GetLeadingWhitespace(document, line); if (line.Length > whitespace.Length) { var text = document.GetText(whitespace) + "//"; document.Replace(whitespace.Offset, whitespace.Length, text, OffsetChangeMappingType.RemoveAndInsert); } line = line.NextLine; } document.EndUpdate(); } [RelayCommand] private void UnComment() { if (RoslynEditorViewModel.CodeEditor == null) { return; } var roslynEditor = RoslynEditorViewModel.CodeEditor; var document = roslynEditor.Document; var startLine = document.GetLineByOffset(roslynEditor.SelectionStart); var endLine = document.GetLineByOffset(roslynEditor.SelectionStart + roslynEditor.SelectionLength); document.BeginUpdate(); var line = startLine; while (line != null && line.LineNumber <= endLine.LineNumber) { var whitespace = TextUtilities.GetLeadingWhitespace(document, line); if (line.Length > whitespace.Length + 2) { var text = document.GetText(whitespace.EndOffset, 2); if (text == "//") document.Remove(whitespace.EndOffset, 2); } line = line.NextLine; } document.EndUpdate(); } //public void Receive(string message) //{ // this.Text = message; //} } }