1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-18 08:06:04 +02:00

Serialize IDE collapse state

This commit is contained in:
Brian Fiete 2022-07-12 05:53:22 -04:00
parent aa58c864f7
commit 4c2530e227
4 changed files with 224 additions and 6 deletions

View file

@ -4,7 +4,8 @@ namespace System.IO
{
class MemoryStream : Stream
{
List<uint8> mMemory ~ delete _;
bool mOwns;
List<uint8> mMemory ~ { if (mOwns) delete _; }
int mPosition = 0;
public override int64 Position
@ -46,14 +47,18 @@ namespace System.IO
public this()
{
mOwns = true;
mMemory = new List<uint8>();
}
public this(List<uint8> memory)
public this(List<uint8> memory, bool owns = true)
{
mOwns = owns;
mMemory = memory;
}
public List<uint8> Memory => mMemory;
public override Result<int> TryRead(Span<uint8> data)
{
let count = data.Length;

View file

@ -57,6 +57,14 @@ namespace IDE
String mWorkspaceDir = new String() ~ delete _;
bool mWantWorkspaceCleanup;
public bool mDisabled;
Dictionary<String, List<uint8>> mDB = new .() ~ DeleteDictionaryAndKeysAndValues!(_);
public bool mDBDirty;
public String mDBWorkspaceDir = new String() ~ delete _;
public this()
{
}
public ~this()
{
@ -84,6 +92,26 @@ namespace IDE
bool wantWorkspaceCleanup = false;
using (mMonitor.Enter())
{
if (mDBDirty)
{
String recoverPath = scope String();
recoverPath.Append(mWorkspaceDir);
recoverPath.Append("/recovery/db.bin");
FileStream fs = scope .();
if (fs.Create(recoverPath) case .Ok)
{
fs.Write((uint32)0xBEEF0701);
for (var kv in mDB)
{
fs.WriteStrSized32(kv.key).IgnoreError();
fs.Write((int32)kv.value.Count);
fs.TryWrite(kv.value).IgnoreError();
}
}
mDBDirty = false;
}
for (var entry in mFileSet)
{
if (entry.mRecoveryFileName == null)
@ -250,6 +278,104 @@ namespace IDE
}
}
public void CheckDB()
{
if (mDBWorkspaceDir == gApp.mWorkspace.mDir)
return;
using (mMonitor.Enter())
{
for (var kv in mDB)
{
delete kv.key;
delete kv.value;
}
mDB.Clear();
mDBWorkspaceDir.Set(gApp.mWorkspace.mDir);
if (mDBWorkspaceDir.IsEmpty)
return;
String recoverPath = scope String();
recoverPath.Append(mDBWorkspaceDir);
recoverPath.Append("/recovery/db.bin");
FileStream fs = scope .();
if (fs.Open(recoverPath) case .Ok)
{
if (fs.Read<uint32>() == 0xBEEF0701)
{
String filePath = scope .();
while (true)
{
filePath.Clear();
if (fs.ReadStrSized32(filePath) case .Err)
break;
if (filePath.IsEmpty)
break;
int32 dataSize = fs.Read<int32>();
List<uint8> list = new List<uint8>();
mDB[new String(filePath)] = list;
list.Resize(dataSize);
if (fs.TryRead(.(list.Ptr, dataSize)) case .Err)
break;
}
}
}
}
}
public void SetDB(StringView key, Span<uint8> data)
{
using (mMonitor.Enter())
{
CheckDB();
if (mDB.TryAddAlt(key, var keyPtr, var valuePtr))
{
*keyPtr = new .(key);
*valuePtr = new .();
}
(*valuePtr).Clear();
(*valuePtr).AddRange(data);
mDBDirty = true;
}
}
public bool GetDB(StringView key, List<uint8> data)
{
using (mMonitor.Enter())
{
CheckDB();
if (mDB.TryGetAlt(key, var matchKey, var value))
{
data.AddRange(value);
return true;
}
return false;
}
}
public bool DeleteDB(StringView key)
{
using (mMonitor.Enter())
{
CheckDB();
if (mDB.GetAndRemoveAlt(key) case .Ok((var mapKey, var value)))
{
mDBDirty = true;
delete mapKey;
delete value;
return true;
}
return false;
}
}
public void Update()
{
if (mProcessingEvent != null)
@ -261,7 +387,7 @@ namespace IDE
using (mMonitor.Enter())
{
if ((!mDirty) && (!mWantWorkspaceCleanup))
if ((!mDirty) && (!mDBDirty) && (!mWantWorkspaceCleanup))
return;
}

View file

@ -14,6 +14,8 @@ using IDE.Debugger;
using IDE.Compiler;
using Beefy.geom;
using Beefy.events;
using System.Security.Cryptography;
using System.IO;
namespace IDE.ui
{
@ -656,6 +658,8 @@ namespace IDE.ui
public int32 mParseRevision;
public int32 mTextRevision;
public bool mDeleted;
public bool DefaultOpen => mKind != .Region;
}
public struct EmitData
@ -812,6 +816,8 @@ namespace IDE.ui
public int32 mCollapseTextVersionId;
public bool mCollapseNeedsUpdate;
public bool mCollapseNoCheckOpen;
public bool mCollapseDBDirty;
public bool mCollapseAwaitingDB = true;
public List<PersistentTextPosition> PersistentTextPositions
{
@ -5950,7 +5956,8 @@ namespace IDE.ui
for (var collapseData in ref data.mCollapseData)
{
if (mCollapseMap.TryAdd(collapseData.mAnchorId, ?, var entry))
bool isNew = mCollapseMap.TryAdd(collapseData.mAnchorId, ?, var entry);
if (isNew)
{
*entry = .();
}
@ -5959,6 +5966,12 @@ namespace IDE.ui
entry.mPrevAnchorLine = prevAnchorLine;
entry.mParseRevision = mCollapseParseRevision;
entry.mDeleted = false;
if ((isNew) && (!entry.DefaultOpen) && (!mCollapseAwaitingDB))
{
// Likely a '#region' that we need to serialize as being open
mCollapseDBDirty = true;
}
}
for (var entry in ref mCollapseMap.Values)
@ -6026,6 +6039,50 @@ namespace IDE.ui
}
}
if ((mCollapseAwaitingDB) && (mSourceViewPanel != null))
{
String filePath = scope .(mSourceViewPanel.mFilePath);
IDEUtils.MakeComparableFilePath(filePath);
HashSet<int32> toggledIndices = scope .();
List<uint8> dbData = scope .();
if (gApp.mFileRecovery.GetDB(filePath, dbData))
{
MemoryStream memStream = scope .(dbData, false);
var dbHash = memStream.Read<MD5Hash>().GetValueOrDefault();
String text = scope .();
mEditWidget.GetText(text);
var curHash = MD5.Hash(.((uint8*)text.Ptr, text.Length));
if (curHash == dbHash)
{
while (true)
{
if (memStream.Read<int32>() case .Ok(let idx))
{
// We recorded indices, which (upon load) will generate an id of idx+1
toggledIndices.Add(idx + 1);
}
else
break;
}
}
}
for (var collapseEntry in mOrderedCollapseEntries)
{
bool wantOpen = collapseEntry.DefaultOpen;
if (toggledIndices.Contains(collapseEntry.mAnchorId))
wantOpen = !wantOpen;
if (collapseEntry.mIsOpen != wantOpen)
SetCollapseOpen(@collapseEntry.Index, wantOpen, true);
}
mCollapseAwaitingDB = false;
}
//Debug.WriteLine($"ParseCollapseRegions Count:{mOrderedCollapseEntries.Count} Time:{sw.ElapsedMilliseconds}ms");
}
@ -6335,8 +6392,8 @@ namespace IDE.ui
entry.mIsOpen = wantOpen;
if (immediate)
entry.mOpenPct = entry.mIsOpen ? 1.0f : 0.0f;
else
mCollapseNeedsUpdate = true;
mCollapseDBDirty = true;
var cursorLineAndColumn = CursorLineAndColumn;

View file

@ -6951,6 +6951,36 @@ namespace IDE.ui
// Process after mQueuedCollapseData so mCharIdSpan is still valid
ProcessDeferredResolveResults(0);
if (ewc.mCollapseDBDirty)
{
MemoryStream memStream = scope .();
String text = scope .();
mEditWidget.GetText(text);
var hash = MD5.Hash(.((uint8*)text.Ptr, text.Length));
memStream.Write(hash);
bool hadData = false;
for (var kv in ewc.mOrderedCollapseEntries)
{
if (kv.mIsOpen != kv.DefaultOpen)
{
hadData = true;
memStream.Write(kv.mAnchorIdx);
}
}
String filePath = scope .(mFilePath);
IDEUtils.MakeComparableFilePath(filePath);
if (!hadData)
gApp.mFileRecovery.DeleteDB(filePath);
else
gApp.mFileRecovery.SetDB(filePath, memStream.Memory);
ewc.mCollapseDBDirty = false;
}
}
public override void UpdateF(float updatePct)