1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 12:32:20 +02:00
Beef/IDE/src/ui/RenameSymbolDialog.bf
2020-05-31 07:12:17 -07:00

1081 lines
33 KiB
Beef

using System;
using System.Collections;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.widgets;
using Beefy.theme.dark;
using Beefy.gfx;
using Beefy.events;
using IDE.Compiler;
using IDE.Util;
using Beefy.utils;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace IDE.ui
{
public class SymbolReferenceHelper : Widget
{
public enum Kind
{
Rename,
ShowFileReferences,
FindAllReferences,
GoToDefinition
}
struct ReplaceSpan
{
public int32 mSpanStart;
public int32 mSpanLength;
}
class ReplaceSymbolData
{
public FileEditData mFileEditData;
public List<ReplaceSpan> mSpans = new List<ReplaceSpan>() ~ delete _;
public bool mIsLocked;
}
enum BackgroundKind
{
None,
GettingSymbolReferences
}
public bool mInitialized;
public bool mFailed;
public bool mGettingSymbolInfo;
public bool mStartedWork;
public bool mStartingWork;
public bool mWantsClose;
public SourceViewPanel mSourceViewPanel;
public bool mAwaitingGetSymbolInfo;
bool mOwnsParser;
BfParser mParser ~ if (mOwnsParser) delete _;
BackgroundKind mBackgroundKind;
ResolveParams mResolveParams = new ResolveParams() ~ delete _;
int32 mCursorPos;
double mVertPos;
BfPassInstance mPassInstance;
BfResolvePassData mResolvePassData;
bool mUsingResolvePassData;
String mNewReplaceStr = new String() ~ delete _;
String mReplaceStr = new String() ~ delete _;
String mOrigReplaceStr = new String() ~ delete _;
String mModifiedParsers ~ delete _;
bool mRenameHadChange;
bool mIgnoreTextChanges;
bool mTextChanged;
int32 mStartIdx;
int32 mEndIdx;
int32 mLastDeletedIdx = -1;
bool mSkipNextUpdate;
bool mDoLock;
bool mDidRevert;
bool mClosed;
bool mOverrideSpanLengths;
int32 mUpdateTextCount = 0;
public Kind mKind;
List<ReplaceSymbolData> mUpdatingProjectSources ~ DeleteContainerAndItems!(_);
public bool HasStarted
{
get
{
return mStartedWork;
}
}
public bool IsStarting
{
get
{
return mStartingWork;
}
}
public bool IsRenaming
{
get
{
return mKind == Kind.Rename;
}
}
public bool IsLocked
{
get
{
return mDoLock;
}
}
/*public this()
{
Debug.WriteLine("SymbolReferenceHelper this {0}", this);
}
public ~this()
{
Debug.WriteLine("SymbolReferenceHelper ~this {0}", this);
}*/
public void Init(SourceViewPanel sourceViewPanel, Kind kind)
{
mSourceViewPanel = sourceViewPanel;
mKind = kind;
mCursorPos = (int32)sourceViewPanel.mEditWidget.Content.CursorTextPos;
mVertPos = sourceViewPanel.mEditWidget.mVertPos.mDest;
mAwaitingGetSymbolInfo = true;
CheckGetSymbolInfo(kind == .ShowFileReferences);
}
void WaitForResolvedAll()
{
while (!gApp.mBfResolveCompiler.HasResolvedAll())
{
gApp.mBfResolveCompiler.WaitForBackground();
gApp.mBfResolveCompiler.Update();
}
}
bool CheckGetSymbolInfo(bool force)
{
if (!mAwaitingGetSymbolInfo)
return true;
if (!force)
{
if (!gApp.mBfResolveCompiler.HasResolvedAll())
return false;
}
mAwaitingGetSymbolInfo = false;
mSourceViewPanel.Classify(.GetSymbolInfo);
mInitialized = true;
mGettingSymbolInfo = true;
return true;
}
public void SetSymbolInfo(String symbolInfo)
{
mGettingSymbolInfo = false;
String foundStr = null;
bool foundSymbol = false;
bool isTypeRef = false;
for (var infoLine in symbolInfo.Split('\n'))
{
var lineDataItr = infoLine.Split('\t');
var dataType = lineDataItr.GetNext().Get();
switch (dataType)
{
case "insertRange":
var dataItr = lineDataItr.GetNext().Get().Split(' ');
mStartIdx = int32.Parse(dataItr.GetNext().Get());
mEndIdx = int32.Parse(dataItr.GetNext().Get());
Debug.Assert(mEndIdx >= mStartIdx);
if (mEndIdx > mStartIdx)
{
foundStr = scope:: String();
mSourceViewPanel.mEditWidget.Content.ExtractString(mStartIdx, mEndIdx - mStartIdx, foundStr);
}
case "localId":
int32 localId = int32.Parse(lineDataItr.GetNext().Get());
mResolveParams.mLocalId = localId;
foundSymbol = true;
case "typeRef":
mOverrideSpanLengths = true;
isTypeRef = true;
mResolveParams.mTypeDef = new String(lineDataItr.GetNext().Get());
foundSymbol = true;
case "fieldRef":
mResolveParams.mTypeDef = new String(lineDataItr.GetNext().Get());
mResolveParams.mFieldIdx = int32.Parse(lineDataItr.GetNext().Get());
foundSymbol = true;
case "methodRef", "ctorRef":
mResolveParams.mTypeDef = new String(lineDataItr.GetNext().Get());
mResolveParams.mMethodIdx = int32.Parse(lineDataItr.GetNext().Get());
foundSymbol = true;
if (dataType == "ctorRef")
{
// For ctor refs, the method name is really 'this' so we can't rename it...
if (mKind != .FindAllReferences)
foundSymbol = false;
}
case "invokeMethodRef":
if (mResolveParams.mTypeDef == null)
{
mResolveParams.mTypeDef = new String(lineDataItr.GetNext().Get());
mResolveParams.mMethodIdx = int32.Parse(lineDataItr.GetNext().Get());
foundSymbol = true;
}
case "propertyRef":
mResolveParams.mTypeDef = new String(lineDataItr.GetNext().Get());
mResolveParams.mPropertyIdx = int32.Parse(lineDataItr.GetNext().Get());
foundSymbol = true;
case "typeGenericParam":
mResolveParams.mTypeGenericParamIdx = int32.Parse(lineDataItr.GetNext().Get());
case "methodGenericParam":
mResolveParams.mMethodGenericParamIdx = int32.Parse(lineDataItr.GetNext().Get());
case "namespaceRef":
mResolveParams.mNamespace = new String(lineDataItr.GetNext().Get());
foundSymbol = true;
case "defLoc":
if (mKind == .Rename)
{
StringView filePath = lineDataItr.GetNext().Get();
let editData = gApp.GetEditData(scope String(filePath), false, false);
if (editData != null)
{
for (var projectSource in editData.mProjectSources)
{
if (projectSource.mProject.mLocked)
{
gApp.Fail(scope String()..AppendF("Symbol definition is located in locked project '{}' and cannot be renamed until the lock is removed.", projectSource.mProject.mProjectName));
mFailed = true;
Close();
return;
}
}
if (editData.IsLocked())
{
gApp.Fail(scope String()..AppendF("Symbol definition is located in locked file '{}' and cannot be renamed until the lock is removed.", filePath));
mFailed = true;
Close();
return;
}
}
}
}
}
if ((!foundSymbol) || (foundStr == null))
{
if ((mKind == .Rename) || (mKind == .FindAllReferences))
IDEApp.sApp.Fail("Unable to locate symbol");
mFailed = true;
Close();
return;
}
if (foundStr != null)
mReplaceStr.Set(foundStr);
if ((isTypeRef) && (mReplaceStr.EndsWith("Attribute")))
{
mReplaceStr.RemoveFromEnd("Attribute".Length);
mEndIdx = mStartIdx + (.)mReplaceStr.Length;
}
if ((mKind == .Rename) && (mEndIdx > 0))
{
var ewc = (SourceEditWidgetContent)mSourceViewPanel.mEditWidget.mEditWidgetContent;
for (int i = mStartIdx; i < mEndIdx; i++)
{
ewc.mData.mText[i].mDisplayFlags |= (uint8)(SourceElementFlags.SymbolReference);
}
// We do the full-selection in the normal case, but if we've moved the cursor since starting the rename
// then that would have removed the selection anyway so we don't do the full-select in that case
if (ewc.CursorTextPos == mCursorPos)
{
ewc.mSelection = EditSelection(mStartIdx, mEndIdx);
ewc.CursorTextPos = mEndIdx;
}
}
mNewReplaceStr.Set(mReplaceStr);
mOrigReplaceStr.Set(mReplaceStr);
}
void PrintAllReferences()
{
gApp.ShowFindResults(false);
gApp.mFindResultsPanel.Clear();
gApp.mFindResultsPanel.QueueLine("Symbol results:");
for (int32 sourceIdx = 0; sourceIdx < mUpdatingProjectSources.Count; sourceIdx++)
{
var replaceSymbolData = mUpdatingProjectSources[sourceIdx];
//var projectSource = replaceSymbolData.mProjectSource;
//var editData = IDEApp.sApp.GetEditData(replaceSymbolData.mProjectSource, true);
var editData = replaceSymbolData.mFileEditData;
List<int32> sortedIndices = scope List<int32>();
for (int32 i = 0; i < replaceSymbolData.mSpans.Count; i++)
{
int32 spanStart = replaceSymbolData.mSpans[i].mSpanStart;
//int32 spanLen = replaceSymbolData.mSpans[i].mSpanLength;
sortedIndices.Add(spanStart);
}
sortedIndices.Sort(scope (a, b) => b - a);
int32 lineStart = 0;
int32 lineNum = 0;
bool wantsLine = false;
var editWidgetContent = editData.mEditWidget.mEditWidgetContent;
for (int32 idx < editWidgetContent.mData.mTextLength)
{
char8 c = editWidgetContent.mData.mText[idx].mChar;
if (c == '\n')
{
if (wantsLine)
{
String lineStr = scope String();
editWidgetContent.ExtractString(lineStart, idx - lineStart, lineStr);
//String fileName = editData.mFilePath;
//String fileName = scope String();
//projectSource.GetFullImportPath(fileName);
gApp.mFindResultsPanel.QueueLine(editData, lineNum, 0, lineStr);
wantsLine = false;
}
lineNum++;
lineStart = idx + 1;
}
if ((sortedIndices.Count > 0) && (idx == sortedIndices[sortedIndices.Count - 1]))
{
sortedIndices.PopBack();
wantsLine = true;
}
}
//editData.mEditWidget.Index
}
}
void DoWork()
{
//TODO:
//Thread.Sleep(2000);
Debug.Assert(mStartingWork);
var bfSystem = IDEApp.sApp.mBfResolveSystem;
var bfCompiler = IDEApp.sApp.mBfResolveCompiler;
bfSystem.Lock(2);
mUsingResolvePassData = true;
bfCompiler.GetSymbolReferences(mPassInstance, mResolvePassData, mModifiedParsers);
mUsingResolvePassData = false;
bfSystem.Unlock();
}
void StartWork()
{
var bfSystem = IDEApp.sApp.mBfResolveSystem;
var bfCompiler = IDEApp.sApp.mBfResolveCompiler;
Debug.Assert(!mGettingSymbolInfo);
StopWork();
mStartedWork = true;
mStartingWork = true;
Debug.Assert(mParser == null);
if ((mKind == Kind.ShowFileReferences) || (mResolveParams.mLocalId != -1))
{
mParser = IDEApp.sApp.mBfResolveSystem.FindParser(mSourceViewPanel.mProjectSource);
if ((mResolveParams != null) && (mResolveParams.mLocalId != -1))
mParser.SetAutocomplete(mCursorPos);
else
mParser.SetAutocomplete(-1);
}
else
{
mParser = new BfParser(null);
mOwnsParser = true;
}
mPassInstance = bfSystem.CreatePassInstance();
mResolvePassData = mParser.CreateResolvePassData(((mKind == Kind.Rename) || (mKind == Kind.FindAllReferences)) ? ResolveType.RenameSymbol : ResolveType.ShowFileSymbolReferences);
var resolveParams = mResolveParams;
if (resolveParams != null)
{
if (resolveParams.mTypeDef != null)
mResolvePassData.SetSymbolReferenceTypeDef(resolveParams.mTypeDef);
if (resolveParams.mFieldIdx != -1)
mResolvePassData.SetSymbolReferenceFieldIdx(resolveParams.mFieldIdx);
if (resolveParams.mMethodIdx != -1)
mResolvePassData.SetSymbolReferenceMethodIdx(resolveParams.mMethodIdx);
if (resolveParams.mPropertyIdx != -1)
mResolvePassData.SetSymbolReferencePropertyIdx(resolveParams.mPropertyIdx);
if (resolveParams.mLocalId != -1)
mResolvePassData.SetLocalId(resolveParams.mLocalId);
if (resolveParams.mTypeGenericParamIdx != -1)
mResolvePassData.SetTypeGenericParamIdx(resolveParams.mTypeGenericParamIdx);
if (resolveParams.mMethodGenericParamIdx != -1)
mResolvePassData.SetMethodGenericParamIdx(resolveParams.mMethodGenericParamIdx);
if (resolveParams.mNamespace != null)
mResolvePassData.SetSymbolReferenceNamespace(resolveParams.mNamespace);
}
mDoLock = mKind == Kind.Rename;
Debug.Assert(mModifiedParsers == null);
mModifiedParsers = new String();
bool doBackground = true;
if (doBackground)
{
bfCompiler.DoBackground(new => DoWork, new => FinishStartingWork);
}
else
{
//TODO: This never locked for find all references. Why not?
bfCompiler.GetSymbolReferences(mPassInstance, mResolvePassData, mModifiedParsers);
FinishStartingWork();
}
}
void FinishStartingWork()
{
var bfSystem = IDEApp.sApp.mBfResolveSystem;
if (mDoLock)
bfSystem.Lock(2);
Debug.Assert(!mUsingResolvePassData);
Debug.Assert(mStartingWork);
mStartingWork = false;
mUpdatingProjectSources = new List<ReplaceSymbolData>();
for (var parserDataStr in mModifiedParsers.Split('\n'))
{
if (parserDataStr == "")
return;
var parserData = parserDataStr.Split('\t');
//var projectSource = IDEApp.sApp.FindProjectSourceItem(parserData[0]);
var filePath = parserData.GetNext().Get();
if ((mKind == .ShowFileReferences) && (!Path.Equals(filePath, mParser.mFileName)))
{
//TODO: Assert?!
continue;
}
ReplaceSymbolData replaceSymbolData = new ReplaceSymbolData();
var editData = gApp.GetEditData(scope String(filePath));
replaceSymbolData.mFileEditData = editData;
//replaceSymbolData.mProjectSource = projectSource;
if (mKind == .Rename)
{
replaceSymbolData.mIsLocked = editData.IsLocked();
}
var spanData = parserData.GetNext().Get().Split(' ');
int count = 0;
while (true)
{
if (spanData.GetNext() case .Err)
break;
count++;
}
spanData.Reset();
count /= 2;
replaceSymbolData.mSpans.Capacity = count;
for (int i < count)
{
ReplaceSpan replaceSpan;
replaceSpan.mSpanStart = int32.Parse(spanData.GetNext().Get());
replaceSpan.mSpanLength = int32.Parse(spanData.GetNext().Get());
if (mOverrideSpanLengths)
replaceSpan.mSpanLength = (.)mReplaceStr.Length;
replaceSymbolData.mSpans.Add(replaceSpan);
}
replaceSymbolData.mSpans.Sort(scope (a, b) => a.mSpanStart - b.mSpanStart);
for (int32 i = 1; i < replaceSymbolData.mSpans.Count; i++)
{
if (replaceSymbolData.mSpans[i - 1].mSpanStart == replaceSymbolData.mSpans[i].mSpanStart)
{
replaceSymbolData.mSpans.RemoveAt(i);
i--;
}
}
mUpdatingProjectSources.Add(replaceSymbolData);
}
if (mKind == Kind.FindAllReferences)
{
PrintAllReferences();
Close();
return;
}
UpdateText();
}
public void EnsureWorkStarted()
{
if (mAwaitingGetSymbolInfo)
{
WaitForResolvedAll();
if (!CheckGetSymbolInfo(false))
return;
mSourceViewPanel.[Friend]ProcessDeferredResolveResults(-1);
StartWork();
}
if (!mStartingWork)
return;
var bfCompiler = IDEApp.sApp.mBfResolveCompiler;
bfCompiler.WaitForBackground();
Debug.Assert(!mStartingWork);
}
void UpdateText()
{
if (mUpdatingProjectSources == null)
return;
mIgnoreTextChanges = true;
String prevReplaceStr = scope String();
prevReplaceStr.Set(mReplaceStr);
int32 strLenDiff = (int32)(mNewReplaceStr.Length - mReplaceStr.Length);
mReplaceStr.Set(mNewReplaceStr);
var activeSourceEditWidgetContent = (SourceEditWidgetContent)mSourceViewPanel.mEditWidget.Content;
String newStr = mReplaceStr;
bool didUndo = false;
if (mKind == .Rename)
{
if (!mRenameHadChange)
{
if (newStr != mOrigReplaceStr)
mRenameHadChange = true;
}
}
GlobalUndoData globalUndoData = null;
if (mKind == Kind.Rename)
globalUndoData = IDEApp.sApp.mGlobalUndoManager.CreateUndoData();
List<int32> cursorPositions = scope List<int32>();
for (var replaceSymbolData in mUpdatingProjectSources)
{
//var editData = IDEApp.sApp.GetEditData(replaceSymbolData.mProjectSource, true);
var editData = replaceSymbolData.mFileEditData;
if (editData.mEditWidget == null)
{
cursorPositions.Add(-1);
continue;
}
var sourceEditWidgetContent = (SourceEditWidgetContent)editData.mEditWidget.Content;
cursorPositions.Add((int32)sourceEditWidgetContent.CursorTextPos);
}
var prevSelection = activeSourceEditWidgetContent.mSelection;
for (int sourceIdx = 0; sourceIdx < mUpdatingProjectSources.Count; sourceIdx++)
{
var replaceSymbolData = mUpdatingProjectSources[sourceIdx];
if (replaceSymbolData.mIsLocked)
continue;
var editData = replaceSymbolData.mFileEditData;
if (editData.mEditWidget == null)
continue;
if ((mKind == Kind.Rename) && (mRenameHadChange))
{
for (var projectSource in editData.mProjectSources)
{
projectSource.HasChangedSinceLastCompile = true;
}
}
int32 cursorPos = cursorPositions[sourceIdx];
var editWidgetContent = editData.mEditWidget.Content;
if ((mUpdateTextCount != 0) && (!didUndo) && (mKind == Kind.Rename))
{
while (true)
{
bool isGlobalBatchEnd = false;
var undoAction = editWidgetContent.mData.mUndoManager.GetLastUndoAction();
if (undoAction is UndoBatchEnd)
{
var undoBatchEnd = (UndoBatchEnd)undoAction;
isGlobalBatchEnd = undoBatchEnd.Name.StartsWith("#");
}
bool success = editWidgetContent.mData.mUndoManager.Undo();
Debug.Assert(success);
if (!success)
break;
if (isGlobalBatchEnd)
break;
}
didUndo = true;
}
SourceEditBatchHelper sourceEditBatchHelper = null;
if (globalUndoData != null)
{
globalUndoData.mFileEditDatas.Add(editData);
sourceEditBatchHelper = scope:: SourceEditBatchHelper(editData.mEditWidget, "#renameSymbol", new GlobalUndoAction(editData, globalUndoData));
}
int32 idxOffset = 0;
for (int32 i = 0; i < replaceSymbolData.mSpans.Count; i++)
{
int32 spanStart = replaceSymbolData.mSpans[i].mSpanStart + idxOffset;
int32 spanLen = replaceSymbolData.mSpans[i].mSpanLength;
if ((mKind == Kind.Rename) &&
((mRenameHadChange) || (editWidgetContent == activeSourceEditWidgetContent)))
{
editWidgetContent.CursorTextPos = spanStart;
var deleteCharAction = new EditWidgetContent.DeleteCharAction(editWidgetContent, 0, spanLen);
deleteCharAction.mMoveCursor = false;
editWidgetContent.mData.mUndoManager.Add(deleteCharAction);
editWidgetContent.PhysDeleteChars(0, spanLen);
editWidgetContent.CursorTextPos = spanStart;
var insertTextAction = new EditWidgetContent.InsertTextAction(editWidgetContent, newStr, .None);
insertTextAction.mMoveCursor = false;
editWidgetContent.mData.mUndoManager.Add(insertTextAction);
editWidgetContent.PhysInsertAtCursor(newStr, false);
if (spanStart <= cursorPos)
cursorPos += strLenDiff;
}
for (int32 attrIdx = spanStart; attrIdx < spanStart + newStr.Length; attrIdx++)
{
editWidgetContent.mData.mText[attrIdx].mDisplayFlags |= (uint8)(SourceElementFlags.SymbolReference);
}
if (mKind == Kind.Rename)
idxOffset += (int32)newStr.Length - spanLen;
}
if (sourceEditBatchHelper != null)
sourceEditBatchHelper.Finish();
// Not a perfect check - theoretically the focus could have changed since renaming is delayed by a tick, not a huge issue...
if ((!mDidRevert) && (editWidgetContent.mEditWidget.mHasFocus) && (mKind == Kind.Rename))
{
editWidgetContent.CursorTextPos = (int32)Math.Max(0, cursorPos - strLenDiff);
}
}
if ((mUpdateTextCount == 0) && (mKind == Kind.Rename))
{
activeSourceEditWidgetContent.mSelection = prevSelection;
}
mUpdateTextCount++;
mIgnoreTextChanges = false;
mDidRevert = false;
}
void StopWork()
{
var bfCompiler = IDEApp.sApp.mBfResolveCompiler;
while (mStartingWork)
{
bfCompiler.CancelBackground();
}
}
void Dispose()
{
mSourceViewPanel.CancelResolve(.GetSymbolInfo);
if (mPassInstance != null)
{
StopWork();
var bfSystem = IDEApp.sApp.mBfResolveSystem;
if (mDoLock)
bfSystem.Unlock();
Debug.Assert(!mUsingResolvePassData);
delete mPassInstance;
mPassInstance = null;
delete mResolvePassData;
mResolvePassData = null;
if (mUpdatingProjectSources != null)
{
if ((mUpdatingProjectSources.IsEmpty) && (mSourceViewPanel.mEditData != null))
{
// If we have an error then won't necessarily even include ourselves, so add this here so we clear out the initial selection
ReplaceSymbolData replaceSymbolData = new ReplaceSymbolData();
replaceSymbolData.mFileEditData = mSourceViewPanel.mEditData;
mUpdatingProjectSources.Add(replaceSymbolData);
}
for (var replaceSymbolData in mUpdatingProjectSources)
{
var editData = replaceSymbolData.mFileEditData;
if (editData.mEditWidget == null)
continue;
var editWidgetContent = editData.mEditWidget.Content;
for (int32 i = 0; i < editWidgetContent.mData.mTextLength; i++)
{
editWidgetContent.mData.mText[i].mDisplayFlags &= 0xFF ^ (uint8)(SourceElementFlags.SymbolReference);
}
using (gApp.mMonitor.Enter())
editData.SetSavedData(null, IdSpan());
var app = IDEApp.sApp;
if ((mKind == Kind.Rename) && (IDEApp.IsBeefFile(editData.mFilePath)))
{
for (var projectSource in editData.mProjectSources)
app.mBfResolveCompiler.QueueProjectSource(projectSource, .None, false);
app.mBfResolveCompiler.QueueDeferredResolveAll();
}
}
}
}
}
void RenameSymbolSubmit(bool isFinal)
{
//var editWidgetContent = mSourceViewPanel.mEditWidget;
UpdateText();
}
public void Cancel()
{
if ((mUpdatingProjectSources != null) && (mKind == Kind.Rename))
{
for (var replaceSymbolData in mUpdatingProjectSources)
{
if (replaceSymbolData.mIsLocked)
continue;
var editData = replaceSymbolData.mFileEditData;
var editWidgetContent = editData.mEditWidget.Content;
while (true)
{
bool isGlobalBatchEnd = false;
var undoAction = editWidgetContent.mData.mUndoManager.GetLastUndoAction();
if (undoAction is UndoBatchEnd)
{
var undoBatchEnd = (UndoBatchEnd)undoAction;
isGlobalBatchEnd = undoBatchEnd.Name.StartsWith("#");
}
bool success = editWidgetContent.mData.mUndoManager.Undo();
Debug.Assert(success);
if (!success)
break;
if (isGlobalBatchEnd)
break;
}
break;
}
}
Close();
}
public override void Update()
{
base.Update();
if (mKind == .GoToDefinition)
{
if (gApp.mBfResolveCompiler.HasResolvedAll())
{
Close();
gApp.GoToDefinition(true);
}
if (mSourceViewPanel.EditWidget.Content.CursorTextPos != mCursorPos)
{
Close();
}
return;
}
if (mAwaitingGetSymbolInfo)
{
if (!CheckGetSymbolInfo(false))
return;
}
if (mStartingWork)
return;
/*if (mReplaceStr == "")
{
//Cancel();
//return;
mReplaceStr = " ";
}
else*/ if (mTextChanged)
{
mTextChanged = false;
UpdateText();
}
//var bfSystem = IDEApp.sApp.mBfResolveSystem;
var bfCompiler = IDEApp.sApp.mBfResolveCompiler;
if ((!mStartedWork) && (bfCompiler != null))
{
bool hasWorkLeft = bfCompiler.IsPerformingBackgroundOperation();
if (mSourceViewPanel.[Friend]mWantsFullClassify)
hasWorkLeft = true;
if (mSourceViewPanel.HasDeferredResolveResults())
hasWorkLeft = true;
if (!hasWorkLeft)
{
StartWork();
}
}
}
public override bool Contains(float x, float y)
{
if (mKind == Kind.ShowFileReferences)
return false;
return base.Contains(x, y);
}
public void Close()
{
if (mClosed)
return;
mClosed = true;
mSourceViewPanel.CancelResolve(.GetSymbolInfo);
if (mBackgroundKind != .None)
{
gApp.mBfResolveCompiler.CancelBackground();
Debug.Assert(mBackgroundKind == .None);
}
if (mParent != null)
RemoveSelf();
if (mKind == .Rename)
mSourceViewPanel.QueueFullRefresh(false);
mSourceViewPanel.mRenameSymbolDialog = null;
IDEApp.sApp.mSymbolReferenceHelper = null;
Dispose();
BFApp.sApp.DeferDelete(this);
}
public override void Draw(Graphics g)
{
if (mKind == Kind.ShowFileReferences)
return;
int symCount = 0;
int readOnlyRefCount = 0;
int lockedFileCount = 0;
if (mUpdatingProjectSources != null)
{
for (var replaceSymbolData in mUpdatingProjectSources)
{
symCount += replaceSymbolData.mSpans.Count;
if (replaceSymbolData.mIsLocked)
{
lockedFileCount++;
readOnlyRefCount += replaceSymbolData.mSpans.Count;
}
}
}
float boxHeight = mHeight - GS!(8);
if (lockedFileCount > 0)
{
boxHeight += GS!(14);
}
base.Draw(g);
using (g.PushColor((lockedFileCount == 0) ? 0xFFFFFFFF : 0xFFF0B0B0))
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Menu), 0, 0, mWidth - GS!(8), boxHeight);
using (g.PushColor(0xFFE0E0E0))
{
g.SetFont(DarkTheme.sDarkTheme.mSmallBoldFont);
float border = GS!(8);
String drawStr = null;
if (!mOrigReplaceStr.IsEmpty)
{
var formatStr = mKind == .FindAllReferences ? "Finding '{0}'" : "Renaming '{0}'";
drawStr = scope:: String()..AppendF(formatStr, mOrigReplaceStr);
}
else
{
switch (mKind)
{
case .FindAllReferences, .GoToDefinition:
drawStr = "Finding...";
case .Rename:
drawStr = "Renaming...";
default:
}
}
if (drawStr != null)
g.DrawString(drawStr, border, GS!(5), FontAlign.Centered, mWidth - border * 2 - GS!(8), FontOverflowMode.Ellipsis);
if (mUpdatingProjectSources != null)
{
g.SetFont(DarkTheme.sDarkTheme.mSmallFont);
var drawString = scope String();
drawString.AppendF("{0} {1} in {2} {3}",
symCount, (symCount == 1) ? "reference" : "references",
mUpdatingProjectSources.Count, (mUpdatingProjectSources.Count == 1) ? "file" : "files");
g.DrawString(drawString, GS!(8), GS!(22), FontAlign.Centered, mWidth - GS!(8) - GS!(16));
if (lockedFileCount > 0)
{
g.SetFont(DarkTheme.sDarkTheme.mSmallBoldFont);
using (g.PushColor(((mUpdateCnt > 200) || (mUpdateCnt / 10 % 2 == 0)) ? 0xFFFF7070 : 0xFFFFB0B0))
g.DrawString(scope String()..AppendF("{} {} LOCKED!", lockedFileCount, (lockedFileCount == 1) ? "FILE" : "FILES"),
GS!(8), GS!(38), FontAlign.Centered, mWidth - GS!(8) - GS!(16));
}
}
}
if ((mUpdatingProjectSources == null) && (mUpdateCnt > 30))
IDEUtils.DrawWait(g, mWidth / 2, mHeight / 2 + 4, mUpdateCnt);
}
public void SourcePreInsertText(SourceEditWidgetContent sourceEditWidgetContent, int index, String text)
{
if (mIgnoreTextChanges)
return;
if (mStartingWork)
return;
bool hadSel = false;
if ((mTextChanged) && (sourceEditWidgetContent.HasSelection()))
{
hadSel = true;
}
if ((mNewReplaceStr == "") && (index == mLastDeletedIdx))
{
mNewReplaceStr.Set(text);
mSkipNextUpdate = true;
mTextChanged = true;
return;
}
// Close if insert is outside match area
if ((index > 0) && (index < sourceEditWidgetContent.mData.mTextLength) &&
((sourceEditWidgetContent.mData.mText[index - 1].mDisplayFlags & (uint8)(SourceElementFlags.SymbolReference)) == 0) &&
((sourceEditWidgetContent.mData.mText[index].mDisplayFlags & (uint8)(SourceElementFlags.SymbolReference)) == 0))
{
Close();
}
}
public void SourcePreRemoveText(SourceEditWidgetContent sourceEditWidgetContent, int index, int length)
{
if (mIgnoreTextChanges)
return;
if (mStartingWork)
return;
// Close if any char8 isn't within the match area
bool isValid = true;
for (int i = index; i < index + length; i++)
{
if ((sourceEditWidgetContent.mData.mText[i].mDisplayFlags & (uint8)(SourceElementFlags.SymbolReference)) == 0)
isValid = false;
}
mLastDeletedIdx = (int32)index;
if (!isValid)
Close();
}
public void SourceUpdateText(SourceEditWidgetContent sourceEditWidgetContent, int index)
{
if (mKind == Kind.ShowFileReferences)
{
Close();
return;
}
if (mSkipNextUpdate)
{
mSkipNextUpdate = false;
return;
}
if (mIgnoreTextChanges)
return;
int left = index;
while (left > 0)
{
if ((sourceEditWidgetContent.mData.mText[left - 1].mDisplayFlags & (uint8)(SourceElementFlags.SymbolReference)) == 0)
break;
left--;
}
int right = index;
while (right < sourceEditWidgetContent.mData.mTextLength)
{
if ((sourceEditWidgetContent.mData.mText[right].mDisplayFlags & (uint8)(SourceElementFlags.SymbolReference)) == 0)
break;
right++;
}
mNewReplaceStr.Clear();
sourceEditWidgetContent.ExtractString(left, right - left, mNewReplaceStr);
mTextChanged = true;
}
public void Revert()
{
mDidRevert = true;
if (mNewReplaceStr == mOrigReplaceStr)
{
Cancel();
}
else
{
mNewReplaceStr.Set(mOrigReplaceStr);
mTextChanged = true;
}
}
}
}