mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-18 16:10:26 +02:00
Serialize IDE collapse state
This commit is contained in:
parent
aa58c864f7
commit
4c2530e227
4 changed files with 224 additions and 6 deletions
|
@ -4,7 +4,8 @@ namespace System.IO
|
||||||
{
|
{
|
||||||
class MemoryStream : Stream
|
class MemoryStream : Stream
|
||||||
{
|
{
|
||||||
List<uint8> mMemory ~ delete _;
|
bool mOwns;
|
||||||
|
List<uint8> mMemory ~ { if (mOwns) delete _; }
|
||||||
int mPosition = 0;
|
int mPosition = 0;
|
||||||
|
|
||||||
public override int64 Position
|
public override int64 Position
|
||||||
|
@ -46,14 +47,18 @@ namespace System.IO
|
||||||
|
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
|
mOwns = true;
|
||||||
mMemory = new List<uint8>();
|
mMemory = new List<uint8>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public this(List<uint8> memory)
|
public this(List<uint8> memory, bool owns = true)
|
||||||
{
|
{
|
||||||
|
mOwns = owns;
|
||||||
mMemory = memory;
|
mMemory = memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<uint8> Memory => mMemory;
|
||||||
|
|
||||||
public override Result<int> TryRead(Span<uint8> data)
|
public override Result<int> TryRead(Span<uint8> data)
|
||||||
{
|
{
|
||||||
let count = data.Length;
|
let count = data.Length;
|
||||||
|
|
|
@ -57,6 +57,14 @@ namespace IDE
|
||||||
String mWorkspaceDir = new String() ~ delete _;
|
String mWorkspaceDir = new String() ~ delete _;
|
||||||
bool mWantWorkspaceCleanup;
|
bool mWantWorkspaceCleanup;
|
||||||
public bool mDisabled;
|
public bool mDisabled;
|
||||||
|
Dictionary<String, List<uint8>> mDB = new .() ~ DeleteDictionaryAndKeysAndValues!(_);
|
||||||
|
public bool mDBDirty;
|
||||||
|
public String mDBWorkspaceDir = new String() ~ delete _;
|
||||||
|
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
{
|
{
|
||||||
|
@ -84,6 +92,26 @@ namespace IDE
|
||||||
bool wantWorkspaceCleanup = false;
|
bool wantWorkspaceCleanup = false;
|
||||||
using (mMonitor.Enter())
|
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)
|
for (var entry in mFileSet)
|
||||||
{
|
{
|
||||||
if (entry.mRecoveryFileName == null)
|
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()
|
public void Update()
|
||||||
{
|
{
|
||||||
if (mProcessingEvent != null)
|
if (mProcessingEvent != null)
|
||||||
|
@ -261,7 +387,7 @@ namespace IDE
|
||||||
|
|
||||||
using (mMonitor.Enter())
|
using (mMonitor.Enter())
|
||||||
{
|
{
|
||||||
if ((!mDirty) && (!mWantWorkspaceCleanup))
|
if ((!mDirty) && (!mDBDirty) && (!mWantWorkspaceCleanup))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ using IDE.Debugger;
|
||||||
using IDE.Compiler;
|
using IDE.Compiler;
|
||||||
using Beefy.geom;
|
using Beefy.geom;
|
||||||
using Beefy.events;
|
using Beefy.events;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace IDE.ui
|
namespace IDE.ui
|
||||||
{
|
{
|
||||||
|
@ -656,6 +658,8 @@ namespace IDE.ui
|
||||||
public int32 mParseRevision;
|
public int32 mParseRevision;
|
||||||
public int32 mTextRevision;
|
public int32 mTextRevision;
|
||||||
public bool mDeleted;
|
public bool mDeleted;
|
||||||
|
|
||||||
|
public bool DefaultOpen => mKind != .Region;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct EmitData
|
public struct EmitData
|
||||||
|
@ -812,6 +816,8 @@ namespace IDE.ui
|
||||||
public int32 mCollapseTextVersionId;
|
public int32 mCollapseTextVersionId;
|
||||||
public bool mCollapseNeedsUpdate;
|
public bool mCollapseNeedsUpdate;
|
||||||
public bool mCollapseNoCheckOpen;
|
public bool mCollapseNoCheckOpen;
|
||||||
|
public bool mCollapseDBDirty;
|
||||||
|
public bool mCollapseAwaitingDB = true;
|
||||||
|
|
||||||
public List<PersistentTextPosition> PersistentTextPositions
|
public List<PersistentTextPosition> PersistentTextPositions
|
||||||
{
|
{
|
||||||
|
@ -5950,7 +5956,8 @@ namespace IDE.ui
|
||||||
|
|
||||||
for (var collapseData in ref data.mCollapseData)
|
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 = .();
|
*entry = .();
|
||||||
}
|
}
|
||||||
|
@ -5959,6 +5966,12 @@ namespace IDE.ui
|
||||||
entry.mPrevAnchorLine = prevAnchorLine;
|
entry.mPrevAnchorLine = prevAnchorLine;
|
||||||
entry.mParseRevision = mCollapseParseRevision;
|
entry.mParseRevision = mCollapseParseRevision;
|
||||||
entry.mDeleted = false;
|
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)
|
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");
|
//Debug.WriteLine($"ParseCollapseRegions Count:{mOrderedCollapseEntries.Count} Time:{sw.ElapsedMilliseconds}ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6335,8 +6392,8 @@ namespace IDE.ui
|
||||||
entry.mIsOpen = wantOpen;
|
entry.mIsOpen = wantOpen;
|
||||||
if (immediate)
|
if (immediate)
|
||||||
entry.mOpenPct = entry.mIsOpen ? 1.0f : 0.0f;
|
entry.mOpenPct = entry.mIsOpen ? 1.0f : 0.0f;
|
||||||
else
|
|
||||||
mCollapseNeedsUpdate = true;
|
mCollapseNeedsUpdate = true;
|
||||||
|
mCollapseDBDirty = true;
|
||||||
|
|
||||||
var cursorLineAndColumn = CursorLineAndColumn;
|
var cursorLineAndColumn = CursorLineAndColumn;
|
||||||
|
|
||||||
|
|
|
@ -6951,6 +6951,36 @@ namespace IDE.ui
|
||||||
|
|
||||||
// Process after mQueuedCollapseData so mCharIdSpan is still valid
|
// Process after mQueuedCollapseData so mCharIdSpan is still valid
|
||||||
ProcessDeferredResolveResults(0);
|
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)
|
public override void UpdateF(float updatePct)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue