using System.ComponentModel; using System.Text; namespace Qrakhen.Qamp.Memory; public struct BufferSpan { public static readonly BufferSpan None = new(0, 0); public int Start { get; set; } = 0; public int End { get; set; } = 0; public bool HasSelection => Start - End != 0; public BufferSpan(int start, int end) { Start = start; End = end; } public BufferSpan Synchronized(TailBuffer source) { return new BufferSpan(Start, Math.Min(End, source.Tail)); } public T[] GetSelectedRegion(TailBuffer source) { return source.Data[Start..End]; } } public class LineBuffer : TailBuffer, INotifyPropertyChanged { public Encoding Encoding { get; } public string Cached { get; private set; } = ""; public event PropertyChangedEventHandler? PropertyChanged; public LineBuffer(Encoding encoding, int size = 0x80) : base(size) { Encoding = encoding; } public LineBuffer(string data) : this(data, Encoding.ASCII) { } public LineBuffer(string data, Encoding encoding) : this(encoding.GetBytes(data), encoding) { } public LineBuffer(byte[] data, Encoding encoding) : base(data) { Encoding = encoding; Cached = ToString(); } protected override void SetTail(int tail = -1) { base.SetTail(tail); Cached = ToString(); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Cached))); } public void Insert(int cursor, string data) => Insert(cursor, Encoding.GetBytes(data)); public string ToString(BufferSpan span) { var synced = span.Synchronized(this); if (!synced.HasSelection) return string.Empty; return Encoding.GetString(Data[synced.Start..synced.End]); } public override string ToString() { if (Tail == 0 || Encoding == null) return string.Empty; return Encoding.GetString(Data, 0, Tail); } public override object Clone() { return new LineBuffer(_data.ToArray(), Encoding); } public static implicit operator LineBuffer(string s) => new LineBuffer(s); }