Replace ReactiveUI
This commit is contained in:
parent
43b4d50e43
commit
5584ab4ec8
41 changed files with 472 additions and 1013 deletions
131
app/InkForge.Desktop/Models/TextDocumentStore.cs
Normal file
131
app/InkForge.Desktop/Models/TextDocumentStore.cs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
using System.Buffers;
|
||||
using System.Text;
|
||||
|
||||
using Avalonia.Collections;
|
||||
|
||||
using AvaloniaEdit.Document;
|
||||
|
||||
using InkForge.Data;
|
||||
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace InkForge.Desktop.Models;
|
||||
|
||||
public class TextDocumentStore(IDbContextFactory<NoteDbContext> dbContextFactory)
|
||||
{
|
||||
private readonly AvaloniaDictionary<int, TextDocument> _cache = [];
|
||||
|
||||
public void Close(int id)
|
||||
{
|
||||
if (_cache.Remove(id, out var document))
|
||||
{
|
||||
document.Remove(0, document.TextLength);
|
||||
}
|
||||
}
|
||||
|
||||
public TextDocument Get(int id)
|
||||
{
|
||||
if (!_cache.TryGetValue(id, out var document))
|
||||
{
|
||||
using var dbContext = dbContextFactory.CreateDbContext();
|
||||
var connection = dbContext.Database.GetDbConnection();
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = $"SELECT rowid FROM Blobs WHERE Id={id}";
|
||||
using var commandReader = command.ExecuteReader();
|
||||
document = new();
|
||||
if (commandReader.Read())
|
||||
{
|
||||
using SqliteBlob stream = new((SqliteConnection)connection, "Blob", "Value", commandReader.GetInt64(0), true);
|
||||
CopyDocumentContent(stream, document);
|
||||
}
|
||||
|
||||
_cache.Add(id, document);
|
||||
}
|
||||
|
||||
return document;
|
||||
|
||||
static void CopyDocumentContent(Stream stream, TextDocument document)
|
||||
{
|
||||
DocumentTextWriter writer = new(document, 0);
|
||||
StreamReader reader = new(stream, Encoding.UTF8);
|
||||
Span<char> buffer = stackalloc char[128];
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
var read = reader.Read(buffer);
|
||||
writer.Write(buffer[..read]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int? Save(int? id, TextDocument textDocument)
|
||||
{
|
||||
var state = textDocument.CreateSnapshot();
|
||||
var bytes = TextBytes(state);
|
||||
|
||||
using var dbContext = dbContextFactory.CreateDbContext();
|
||||
var connection = dbContext.Database.GetDbConnection();
|
||||
using var transaction = dbContext.Database.BeginTransaction();
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = id switch
|
||||
{
|
||||
null => $"INSERT INTO Blobs(Value) VALUES(zeroblob({bytes})) RETURNING (Id, rowid)",
|
||||
_ => $"UPDATE Blobs SET Value=zeroblob({bytes}) WHERE Id={id} RETURNING (Id, rowid)"
|
||||
};
|
||||
using var commandReader = command.ExecuteReader();
|
||||
if (!commandReader.Read())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
id = commandReader.GetInt32(0);
|
||||
using (SqliteBlob stream = new((SqliteConnection)connection, "Blobs", "Value", commandReader.GetInt64(1)))
|
||||
{
|
||||
using StreamWriter writer = new(stream, Encoding.UTF8);
|
||||
state.WriteTextTo(writer);
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
_cache.TryAdd((int)id, textDocument);
|
||||
return id;
|
||||
|
||||
static int TextBytes(ITextSource text)
|
||||
{
|
||||
int length = 0;
|
||||
Span<byte> byteBuffer = stackalloc byte[128];
|
||||
using var reader = text.CreateReader();
|
||||
ArrayBufferWriter<char> buffer = new();
|
||||
var encoder = Encoding.UTF8.GetEncoder();
|
||||
while (reader.Peek() != -1)
|
||||
{
|
||||
var memory = buffer.GetMemory();
|
||||
buffer.Advance(reader.Read(memory.Span));
|
||||
ReadOnlySpan<char> chars = buffer.WrittenSpan;
|
||||
|
||||
convert:
|
||||
encoder.Convert(buffer.WrittenSpan, byteBuffer, false, out var charsUsed, out var bytesUsed, out _);
|
||||
chars = chars[charsUsed..];
|
||||
if (bytesUsed > 0)
|
||||
{
|
||||
length += bytesUsed;
|
||||
goto convert;
|
||||
}
|
||||
|
||||
Span<char> remaining = [];
|
||||
if (!chars.IsEmpty)
|
||||
{
|
||||
remaining = buffer.GetSpan(chars.Length);
|
||||
chars.CopyTo(remaining);
|
||||
}
|
||||
|
||||
buffer.Clear();
|
||||
if (!remaining.IsEmpty)
|
||||
{
|
||||
buffer.Write(remaining);
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue