diff --git a/BeefLibs/corlib/src/Reflection/MethodInfo.bf b/BeefLibs/corlib/src/Reflection/MethodInfo.bf index ea6447c2..d9db4b02 100644 --- a/BeefLibs/corlib/src/Reflection/MethodInfo.bf +++ b/BeefLibs/corlib/src/Reflection/MethodInfo.bf @@ -1017,6 +1017,25 @@ namespace System.Reflection strBuffer.Append(')'); } + public void GetMethodSig(String strBuffer) + { + strBuffer.Append('('); + int useParamIdx = 0; + for (int paramIdx < ParamCount) + { + var flag = GetParamFlags(paramIdx); + if (flag.HasFlag(.Implicit)) + continue; + if (useParamIdx > 0) + strBuffer.Append(", "); + if (flag.HasFlag(.Params)) + strBuffer.Append("params "); + strBuffer.Append(GetParamType(paramIdx)); + useParamIdx++; + } + strBuffer.Append(')'); + } + public void GetParamsDecl(String strBuffer) { int useParamIdx = 0; diff --git a/IDE/src/Debugger/DebugManager.bf b/IDE/src/Debugger/DebugManager.bf index abb95fc0..32d2ba4f 100644 --- a/IDE/src/Debugger/DebugManager.bf +++ b/IDE/src/Debugger/DebugManager.bf @@ -432,7 +432,8 @@ namespace IDE.Debugger public int32 mActiveCallStackIdx; public Event mBreakpointsChangedDelegate ~ _.Dispose(); public Breakpoint mRunToCursorBreakpoint; - public int32 mDebugIdx; + public int32 mSessionIdx; + public int32 mStateIdx; public bool IsRunning { @@ -466,6 +467,17 @@ namespace IDE.Debugger Debugger_Delete(); } + public void IncrementSessionIdx() + { + mSessionIdx++; + mStateIdx++; + } + + public void IncrementStateIdx() + { + mStateIdx++; + } + public void Reset() { for (var breakpoint in mBreakpointList) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 04fb7dbd..c7950e74 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -4864,7 +4864,7 @@ namespace IDE { if (mDebugger.mIsRunning) { - if (mExecutionPaused) + if ((mExecutionPaused) && (mDebugger.IsPaused())) { DebuggerUnpaused(); mDebugger.StepInto(IsInDisassemblyMode()); @@ -4882,7 +4882,7 @@ namespace IDE mStepCount++; if (mDebugger.mIsRunning) { - if (mExecutionPaused) + if ((mExecutionPaused) && (mDebugger.IsPaused())) { DebuggerUnpaused(); mDebugger.StepOver(IsInDisassemblyMode()); @@ -4902,7 +4902,7 @@ namespace IDE [IDECommand] void StepOut() { - if (mExecutionPaused) + if ((mExecutionPaused) && (mDebugger.IsPaused())) { DebuggerUnpaused(); mDebugger.StepOut(IsInDisassemblyMode()); @@ -12437,7 +12437,7 @@ namespace IDE CheckDebugVisualizers(); mDebugger.mIsRunning = true; - mDebugger.mDebugIdx++; + mDebugger.IncrementSessionIdx(); WithSourceViewPanels(scope (sourceView) => { sourceView.RehupAlias(); @@ -12496,7 +12496,7 @@ namespace IDE CheckDebugVisualizers(); mDebugger.mIsRunning = true; - mDebugger.mDebugIdx++; + mDebugger.IncrementSessionIdx(); mDebugger.RehupBreakpoints(true); mDebugger.Run(); mIsAttachPendingSourceShow = true; @@ -12969,7 +12969,7 @@ namespace IDE if (mDebugger.OpenMiniDump(mCrashDumpPath)) { mDebugger.mIsRunning = true; - mDebugger.mDebugIdx++; + mDebugger.IncrementSessionIdx(); mExecutionPaused = false; // Make this false so we can detect a Pause immediately mIsAttachPendingSourceShow = true; } @@ -13281,6 +13281,7 @@ namespace IDE void DebuggerPaused() { + mDebugger.IncrementStateIdx(); mDebugger.mActiveCallStackIdx = 0; mExecutionPaused = true; mDebugger.GetRunState(); @@ -13294,6 +13295,8 @@ namespace IDE void WithWatchPanels(delegate void(WatchPanel watchPanel) dlg) { + if (mWatchPanel == null) + return; dlg(mWatchPanel); dlg(mAutoWatchPanel); for (let window in mWindows) diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index d4f47c41..3d539d98 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -153,7 +153,8 @@ namespace IDE public List mSymbolSearchPath = new .() ~ DeleteContainerAndItems!(_); public List mAutoFindPaths = new .() ~ DeleteContainerAndItems!(_); public int32 mProfileSampleRate = 1000; - public bool mAutoEvaluateProperties = false; + public bool mAutoEvaluatePropertiesOnHover = false; + public bool mAutoRefreshWatches = false; public void Serialize(StructuredData sd) { @@ -194,7 +195,8 @@ namespace IDE sd.RemoveIfEmpty(); } sd.Add("ProfileSampleRate", mProfileSampleRate); - sd.Add("AutoEvaluateProperties", mAutoEvaluateProperties); + sd.Add("AutoEvaluateProperties", mAutoEvaluatePropertiesOnHover); + sd.Add("AutoRefreshWatches", mAutoRefreshWatches); } public void Deserialize(StructuredData sd) @@ -233,7 +235,8 @@ namespace IDE } } sd.Get("ProfileSampleRate", ref mProfileSampleRate); - sd.Get("AutoEvaluateProperties", ref mAutoEvaluateProperties); + sd.Get("AutoEvaluateProperties", ref mAutoEvaluatePropertiesOnHover); + sd.Get("AutoRefreshWatches", ref mAutoRefreshWatches); } public void Apply() @@ -264,6 +267,9 @@ namespace IDE gApp.mDebugger.SetSourcePathRemap(remapStr); mProfileSampleRate = Math.Clamp(mProfileSampleRate, 10, 10000); + + gApp.mDebugger.IncrementStateIdx(); + gApp.RefreshWatches(); } public void SetDefaults() @@ -1349,7 +1355,6 @@ namespace IDE mKeySettings.Apply(); mDebuggerSettings.Apply(); - for (var window in gApp.mWindows) { if (var widgetWindow = window as WidgetWindow) diff --git a/IDE/src/TestManager.bf b/IDE/src/TestManager.bf index 04d40ebc..02a63fd5 100644 --- a/IDE/src/TestManager.bf +++ b/IDE/src/TestManager.bf @@ -639,7 +639,7 @@ namespace IDE gApp.mDebugger.RehupBreakpoints(true); gApp.mDebugger.Run(); gApp.mDebugger.mIsRunning = true; - gApp.mDebugger.mDebugIdx++; + gApp.mDebugger.IncrementSessionIdx(); } mTestInstance.mThread.Start(false); diff --git a/IDE/src/ui/AutoComplete.bf b/IDE/src/ui/AutoComplete.bf index 9dc13e96..00a61a6c 100644 --- a/IDE/src/ui/AutoComplete.bf +++ b/IDE/src/ui/AutoComplete.bf @@ -2977,11 +2977,15 @@ namespace IDE.ui //insertText = insertText.Substring(0, insertText.Length - 1); String implText = null; int tabIdx = insertText.IndexOf('\t'); - if (tabIdx != -1) + int splitIdx = tabIdx; + int crIdx = insertText.IndexOf('\r'); + if ((crIdx != -1) && (tabIdx != -1) && (crIdx < tabIdx)) + splitIdx = crIdx; + if (splitIdx != -1) { implText = scope:: String(); - implText.Append(insertText, tabIdx); - insertText.RemoveToEnd(tabIdx); + implText.Append(insertText, splitIdx); + insertText.RemoveToEnd(splitIdx); } String prevText = scope String(); mTargetEditWidget.Content.ExtractString(editSelection.mStartPos, editSelection.mEndPos - editSelection.mStartPos, prevText); diff --git a/IDE/src/ui/HoverWatch.bf b/IDE/src/ui/HoverWatch.bf index b7cd9ac8..0597e6f8 100644 --- a/IDE/src/ui/HoverWatch.bf +++ b/IDE/src/ui/HoverWatch.bf @@ -775,7 +775,7 @@ namespace IDE.ui flags |= DebugManager.EvalExpressionFlags.DeselectCallStackIdx; if (mAllowSideEffects) flags |= .AllowSideEffects | .AllowCalls; - if (gApp.mSettings.mDebuggerSettings.mAutoEvaluateProperties) + if (gApp.mSettings.mDebuggerSettings.mAutoEvaluatePropertiesOnHover) flags |= .AllowProperties; if (watch.mResultType == .RawText) flags |= .RawStr; diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index 340ed4bb..aee5fc3b 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -347,7 +347,8 @@ namespace IDE.ui AddPropertiesItem(root, "Symbol File Locations", "mSymbolSearchPath"); AddPropertiesItem(root, "Auto Find Paths", "mAutoFindPaths"); AddPropertiesItem(root, "Profile Sample Rate", "mProfileSampleRate"); - AddPropertiesItem(root, "Auto Evaluate Properties", "mAutoEvaluateProperties"); + AddPropertiesItem(root, "Auto Eval Properties on Hover", "mAutoEvaluatePropertiesOnHover"); + AddPropertiesItem(root, "Auto Refresh Side Effects", "mAutoRefreshWatches"); } protected override void ResetSettings() diff --git a/IDE/src/ui/WatchPanel.bf b/IDE/src/ui/WatchPanel.bf index 876c794f..00601b6d 100644 --- a/IDE/src/ui/WatchPanel.bf +++ b/IDE/src/ui/WatchPanel.bf @@ -54,6 +54,8 @@ namespace IDE.ui public bool mIsNewExpression; public bool mIsPending; public bool mUsedLock; + public bool? mAutoRefresh; + public int32 mDebuggerStateIdx; public int32 mCurStackIdx; public int mMemoryBreakpointAddr; public int32 mHadStepCount; @@ -66,6 +68,24 @@ namespace IDE.ui public int32 mSeriesFirstVersion = -1; public int32 mSeriesVersion = -1; + public bool AutoRefresh + { + get + { + if (mAutoRefresh != null) + return mAutoRefresh.Value; + return gApp.mSettings.mDebuggerSettings.mAutoRefreshWatches; + } + + set + { + if (value == gApp.mSettings.mDebuggerSettings.mAutoRefreshWatches) + mAutoRefresh = null; + else + mAutoRefresh = value; + } + } + public bool IsConstant { get @@ -1968,7 +1988,32 @@ namespace IDE.ui { mWatchRefreshButton = new WatchRefreshButton(); mWatchRefreshButton.Resize(GS!(-16), 0, GS!(20), GS!(20)); - mWatchRefreshButton.mOnMouseDown.Add(new (evt) => RefreshWatch()); + mWatchRefreshButton.mOnMouseDown.Add(new (evt) => + { + if (evt.mBtn == 0) + RefreshWatch(); + if (evt.mBtn == 1) + { + Menu menu = new Menu(); + Menu anItem; + anItem = menu.AddItem("Refresh"); + anItem.mOnMenuItemSelected.Add(new (item) => { RefreshWatch(); }); + + anItem = menu.AddItem("Auto Refresh"); + if (mWatchEntry.AutoRefresh) + anItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Check); + anItem.mOnMenuItemSelected.Add(new (item) => + { + mWatchEntry.AutoRefresh = !mWatchEntry.AutoRefresh; + if (mWatchEntry.AutoRefresh) + RefreshWatch(); + }); + + MenuWidget menuWidget = ThemeFactory.mDefault.CreateMenuWidget(menu); + menuWidget.Init(mWatchRefreshButton, evt.mX, mHeight + GS!(2)); + } + + }); var typeSubItem = GetSubItem(columnIdx); typeSubItem.AddWidget(mWatchRefreshButton); mListView.mListSizeDirty = true; @@ -2024,7 +2069,7 @@ namespace IDE.ui if ((mDisabled) && (allowRefresh)) { - AddRefreshButton(); + AddRefreshButton(); } else if (mWatchRefreshButton != null) { @@ -2061,7 +2106,7 @@ namespace IDE.ui return retVal; } - void RefreshWatch() + public void RefreshWatch() { var parentWatchListViewItem = mParentItem as WatchListViewItem; if (parentWatchListViewItem != null) @@ -2997,7 +3042,12 @@ namespace IDE.ui for (WatchListViewItem watchListViewItem in childItems) { var watchEntry = watchListViewItem.mWatchEntry; - data.Add(watchEntry.mEvalStr); + using (data.CreateObject()) + { + data.Add("EvalStr", watchEntry.mEvalStr); + if (watchEntry.mAutoRefresh != null) + data.Add("AutoRefresh", watchEntry.mAutoRefresh.Value); + } } } } @@ -3017,14 +3067,23 @@ namespace IDE.ui IDEUtils.DeserializeListViewState(data, mListView); for (let itemKey in data.Enumerate("Items")) { - //for (int32 watchIdx = 0; watchIdx < data.Count; watchIdx++) - //for (var watchKV in data) - { - String watchEntry = scope String(); - //data.GetString(watchIdx, watchEntry); - data.GetCurString(watchEntry); - AddWatch(watchEntry); - } + String watchEntry = scope String(); + data.GetCurString(watchEntry); + WatchListViewItem watchItem; + + if (!watchEntry.IsEmpty) + { + watchItem = AddWatch(watchEntry); + } + else + { + data.GetString("EvalStr", watchEntry); + watchItem = AddWatch(watchEntry); + if (data.Contains("AutoRefresh")) + { + watchItem.mWatchEntry.mAutoRefresh = data.GetBool("AutoRefresh"); + } + } } return true; @@ -3622,6 +3681,12 @@ namespace IDE.ui } else if (watch.mEvalStr.Length > 0) { + if (!gApp.mDebugger.IsPaused()) + { + // Keep waiting + return; + } + String evalStr = scope String(1024); if (watch.mStackFrameId != null) { @@ -3637,6 +3702,7 @@ namespace IDE.ui DebugManager.EvalExpressionFlags flags = .AllowStringView; if (watch.mIsNewExpression) flags |= .AllowSideEffects | .AllowCalls; + gApp.DebugEvaluate(null, evalStr, val, -1, watch.mLanguage, flags); watch.mIsNewExpression = false; } @@ -3666,6 +3732,14 @@ namespace IDE.ui if (((!valueSubItem.mFailed) && (watch.mHadValue)) || (hadSideEffects) || (hadPropertyEval)) { watch.mHasValue = true; + + if ((hadSideEffects) && (watch.AutoRefresh)) + { + if (watch.mDebuggerStateIdx != gApp.mDebugger.mStateIdx) + listViewItem.RefreshWatch(); + return; + } + listViewItem.SetDisabled(true, hadSideEffects); return; } @@ -3730,6 +3804,7 @@ namespace IDE.ui watch.mIsStackAlloc = false; watch.mUsedLock = false; watch.mCurStackIdx = -1; + watch.mDebuggerStateIdx = gApp.mDebugger.mStateIdx; watch.mLanguage = .NotSet; DeleteAndNullify!(watch.mEditInitialize); DeleteAndNullify!(watch.mAction); diff --git a/IDEHelper/WinDebugger.cpp b/IDEHelper/WinDebugger.cpp index 312d8530..327d0849 100644 --- a/IDEHelper/WinDebugger.cpp +++ b/IDEHelper/WinDebugger.cpp @@ -2920,7 +2920,8 @@ bool WinDebugger::DoUpdate() if (!handled) { - OutputMessage(StrFormat("Skipping first chance exception %08X at address %@ in thread %d\n", exceptionRecord->ExceptionCode, exceptionRecord->ExceptionAddress, threadInfo->mThreadId)); + if (mRunState != RunState_DebugEval) + OutputMessage(StrFormat("Skipping first chance exception %08X at address %@ in thread %d\n", exceptionRecord->ExceptionCode, exceptionRecord->ExceptionAddress, threadInfo->mThreadId)); ::ContinueDebugEvent(mDebuggerWaitingThread->mProcessId, mDebuggerWaitingThread->mThreadId, DBG_EXCEPTION_NOT_HANDLED); mIsDebuggerWaiting = false; }