2019-08-23 11:56:54 -07:00
using System ;
2020-04-29 06:40:03 -07:00
using System.Collections ;
2019-08-23 11:56:54 -07:00
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 _ ;
2019-09-07 06:40:03 -07:00
public bool mIsLocked ;
2019-08-23 11:56:54 -07:00
}
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 _ ;
2019-09-07 06:40:03 -07:00
bool mRenameHadChange ;
2019-08-23 11:56:54 -07:00
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 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 ( ) ) ;
2019-09-07 15:18:32 -07:00
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 ;
}
}
}
2019-08-23 11:56:54 -07:00
}
}
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 ) ;
}
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;
2019-09-07 06:40:03 -07:00
if ( mKind = = . Rename )
{
2019-09-07 15:18:32 -07:00
replaceSymbolData . mIsLocked = editData . IsLocked ( ) ;
2019-09-07 06:40:03 -07:00
}
2019-08-23 11:56:54 -07:00
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 ;
2019-09-07 06:40:03 -07:00
2019-08-23 11:56:54 -07:00
String prevReplaceStr = scope String ( ) ;
prevReplaceStr . Set ( mReplaceStr ) ;
int32 strLenDiff = ( int32 ) ( mNewReplaceStr . Length - mReplaceStr . Length ) ;
mReplaceStr . Set ( mNewReplaceStr ) ;
2019-09-07 06:40:03 -07:00
var activeSourceEditWidgetContent = ( SourceEditWidgetContent ) mSourceViewPanel . mEditWidget . Content ;
2019-08-23 11:56:54 -07:00
String newStr = mReplaceStr ;
bool didUndo = false ;
2019-09-07 06:40:03 -07:00
if ( mKind = = . Rename )
{
if ( ! mRenameHadChange )
{
if ( newStr ! = mOrigReplaceStr )
mRenameHadChange = true ;
}
}
GlobalUndoData globalUndoData = null ;
if ( mKind = = Kind . Rename )
globalUndoData = IDEApp . sApp . mGlobalUndoManager . CreateUndoData ( ) ;
2019-08-23 11:56:54 -07:00
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 ) ;
}
2019-09-07 06:40:03 -07:00
var prevSelection = activeSourceEditWidgetContent . mSelection ;
2019-08-23 11:56:54 -07:00
for ( int sourceIdx = 0 ; sourceIdx < mUpdatingProjectSources . Count ; sourceIdx + + )
{
var replaceSymbolData = mUpdatingProjectSources [ sourceIdx ] ;
2019-09-07 06:40:03 -07:00
if ( replaceSymbolData . mIsLocked )
continue ;
2019-08-23 11:56:54 -07:00
var editData = replaceSymbolData . mFileEditData ;
if ( editData . mEditWidget = = null )
continue ;
2019-09-07 06:40:03 -07:00
if ( ( mKind = = Kind . Rename ) & & ( mRenameHadChange ) )
2019-08-23 11:56:54 -07:00
{
2019-09-07 06:40:03 -07:00
for ( var projectSource in editData . mProjectSources )
{
projectSource . HasChangedSinceLastCompile = true ;
}
2019-08-23 11:56:54 -07:00
}
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 ;
2019-09-07 06:40:03 -07:00
if ( ( mKind = = Kind . Rename ) & &
( ( mRenameHadChange ) | | ( editWidgetContent = = activeSourceEditWidgetContent ) ) )
2019-08-23 11:56:54 -07:00
{
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 ) )
{
2019-09-07 06:40:03 -07:00
activeSourceEditWidgetContent . mSelection = prevSelection ;
2019-08-23 11:56:54 -07:00
}
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 )
2020-04-14 11:37:27 -07:00
app . mBfResolveCompiler . QueueProjectSource ( projectSource , . None , false ) ;
2019-08-23 11:56:54 -07:00
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 )
{
2019-09-07 06:40:03 -07:00
if ( replaceSymbolData . mIsLocked )
continue ;
2019-08-23 11:56:54 -07:00
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 ( ) ;
2020-04-07 08:29:54 -07:00
gApp . GoToDefinition ( true ) ;
2019-08-23 11:56:54 -07:00
}
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 ( ) ;
}
}
}
2020-01-25 06:22:06 -08:00
public override bool Contains ( float x , float y )
{
if ( mKind = = Kind . ShowFileReferences )
return false ;
return base . Contains ( x , y ) ;
}
2019-08-23 11:56:54 -07:00
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 ;
2019-09-07 06:40:03 -07:00
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 ) ;
}
2019-08-23 11:56:54 -07:00
base . Draw ( g ) ;
2019-09-07 06:40:03 -07:00
using ( g . PushColor ( ( lockedFileCount = = 0 ) ? 0xFFFFFFFF : 0xFFF0B0B0 ) )
g . DrawBox ( DarkTheme . sDarkTheme . GetImage ( DarkTheme . ImageIdx . Menu ) , 0 , 0 , mWidth - GS ! ( 8 ) , boxHeight ) ;
2019-08-23 11:56:54 -07:00
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 )
2019-09-07 06:40:03 -07:00
g . DrawString ( drawStr , border , GS ! ( 5 ) , FontAlign . Centered , mWidth - border * 2 - GS ! ( 8 ) , FontOverflowMode . Ellipsis ) ;
2019-08-23 11:56:54 -07:00
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 ) ) ;
2019-09-07 06:40:03 -07:00
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 ) ) ;
}
2019-08-23 11:56:54 -07:00
}
}
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 ;
}
}
}
}