using System; using System.IO; using System.Reactive.Linq; using DynamicData; using Intromat.Model.Compiler; using Intromat.PersistentModel; using Intromat.ViewModels; using Intromat.ViewModels.Editors; using Intromat.ViewModels.Previews; using Intromat.Views; using NodeNetwork.Toolkit.ValueNode; using NodeNetwork.Utilities; using ReactiveUI; using RxFileSystemWatcher; using Splat; namespace Intromat.Nodes.Code { public class StringFileNode : CodeGenNodeViewModel { private readonly ObservableAsPropertyHelper _fileWatcher; private readonly ObservableAsPropertyHelper _fullPath; static StringFileNode() { Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor)); } public StringFileNode() : base(NodeType.Literal) { Name = "String (file)"; Path = new CodeGenInputViewModel(EPortType.String) { Name = "Path", Editor = PathEditor, }; Inputs.Add(Path); Contents = new CodeGenOutputViewModel>(EPortType.String) { Name = "Contents", }; var stringPreview = new StringPreviewViewModel(); Preview = stringPreview; this.WhenAnyValue(vm => vm.Parent, vm => vm.Path.Value) .Where(pair => pair.Item1 != null && pair.Item2 != null) .Select(pair => System.IO.Path.Combine(((CodeGenNetworkViewModel)pair.Item1).Document.Parent.FullPath, pair.Item2!)) .StartWith(string.Empty) .ToProperty(this, vm => vm.FullPath, out _fullPath); this.WhenAnyValue(vm => vm.FullPath) .Where(File.Exists) .Select(path => new ObservableFileSystemWatcher(c => { c.Path = System.IO.Path.GetDirectoryName(path)!; })) .ToProperty(this, vm => vm.FileWatcher, out _fileWatcher); Contents.Value = this.WhenAnyValue(vm => vm.FileWatcher) .PairWithPreviousValue() .Select(pair => { var oldWatcher = pair.OldValue; var newWatcher = pair.NewValue; oldWatcher?.Dispose(); if (newWatcher != null) { stringPreview.Value = Path.Value!; var result = newWatcher.Renamed.Where(e => e.FullPath == FullPath) .Merge(newWatcher.Changed.Where(e => e.FullPath == FullPath)) .Throttle(TimeSpan.FromMilliseconds(100)) .Select(_ => new StringLiteralValue() { Value = File.ReadAllText(FullPath) }) .StartWith(new StringLiteralValue() { Value = File.ReadAllText(FullPath) }); newWatcher.Start(); return result; } stringPreview.Value = string.Empty; return Observable.Empty(); }) .Switch(); Outputs.Add(Contents); } public ObservableFileSystemWatcher FileWatcher => _fileWatcher.Value; public string FullPath => _fullPath.Value; public StringValueEditorViewModel PathEditor { get; } = new(); public ValueNodeInputViewModel Path { get; } public ValueNodeOutputViewModel> Contents { get; } public override NodeModelBase CreateModel() { return new StringFileModel(); } public override void LoadModel(NodeModelBase model) { base.LoadModel(model); var fileModel = (StringFileModel)model; PathEditor.Value = fileModel.Value; } public override void SaveModel(NodeModelBase model) { base.SaveModel(model); var fileModel = (StringFileModel)model; fileModel.Value = PathEditor.Value; } } }