Files
bluflame/intromat/Intromat/Nodes/Code/StringFileNode.cs
2026-04-18 22:31:51 +02:00

121 lines
4.2 KiB
C#

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<ObservableFileSystemWatcher> _fileWatcher;
private readonly ObservableAsPropertyHelper<string> _fullPath;
static StringFileNode()
{
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<StringFileNode>));
}
public StringFileNode()
: base(NodeType.Literal)
{
Name = "String (file)";
Path = new CodeGenInputViewModel<string?>(EPortType.String)
{
Name = "Path",
Editor = PathEditor,
};
Inputs.Add(Path);
Contents = new CodeGenOutputViewModel<ITypedExpression<string?>>(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<StringLiteralValue>();
})
.Switch();
Outputs.Add(Contents);
}
public ObservableFileSystemWatcher FileWatcher => _fileWatcher.Value;
public string FullPath => _fullPath.Value;
public StringValueEditorViewModel PathEditor { get; } = new();
public ValueNodeInputViewModel<string?> Path { get; }
public ValueNodeOutputViewModel<ITypedExpression<string?>> 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;
}
}
}