ソースを参照

Improved debugger side effect handling, auto refresh options

Brian Fiete 8 ヶ月 前
コミット
1484a5f53c

+ 19 - 0
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;

+ 13 - 1
IDE/src/Debugger/DebugManager.bf

@@ -432,7 +432,8 @@ namespace IDE.Debugger
 		public int32 mActiveCallStackIdx;
 		public Event<Action> 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)

+ 9 - 6
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)

+ 9 - 4
IDE/src/Settings.bf

@@ -153,7 +153,8 @@ namespace IDE
 			public List<String> mSymbolSearchPath = new .() ~ DeleteContainerAndItems!(_);
 			public List<String> 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)

+ 1 - 1
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);

+ 7 - 3
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);

+ 1 - 1
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;

+ 2 - 1
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()

+ 87 - 12
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);

+ 2 - 1
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;
 						}