Răsfoiți Sursa

Emit marker fixes - idSpan fix, persistent opening, specialized squiggle

Brian Fiete 3 ani în urmă
părinte
comite
866bddde2e

+ 9 - 1
BeefLibs/Beefy2D/src/utils/IdSpan.bf

@@ -3,6 +3,7 @@ using System.Collections;
 using System.Diagnostics;
 using System.Text;
 using System.Threading.Tasks;
+using System.Security.Cryptography;
 
 namespace Beefy.utils
 {
@@ -1061,7 +1062,7 @@ namespace Beefy.utils
 
 				        if (cmd == 0)
 						{
-							outString.Append("}");
+							outString.AppendF($"}} EndIdx:{charIdx}");
 				            return;
 						}
 
@@ -1070,5 +1071,12 @@ namespace Beefy.utils
 				}
 			}
 		}
+
+		public int GetHashCode() mut
+		{
+			Prepare();
+			var hash = MD5.Hash(.(mData, 0, mLength));
+			return *(int*)&hash;
+		}
     }
 }

+ 2 - 2
IDE/src/Compiler/BfCompiler.bf

@@ -555,9 +555,9 @@ namespace IDE.Compiler
 
 	                    var bfParser = mBfSystem.CreateParser(projectSourceCommand.mProjectSource);
 						if (data != null)
-	                        bfParser.SetSource(data, sourceFilePath);
+	                        bfParser.SetSource(data, sourceFilePath, -1);
 						else
-							bfParser.SetSource("", sourceFilePath);
+							bfParser.SetSource("", sourceFilePath, -1);
 						bfParser.SetCharIdData(ref char8IdData);
 
 						if (hash case .MD5(let md5Hash))

+ 3 - 3
IDE/src/Compiler/BfParser.bf

@@ -115,7 +115,7 @@ namespace IDE.Compiler
 		static extern void BfSystem_DeleteParser(void* bfSystem, void* bfParser);
 
         [CallingConvention(.Stdcall), CLink]
-        static extern void BfParser_SetSource(void* bfParser, char8* data, int32 length, char8* fileName);
+        static extern void BfParser_SetSource(void* bfParser, char8* data, int32 length, char8* fileName, int32 textVersion);
 
         [CallingConvention(.Stdcall), CLink]
         static extern void BfParser_SetCharIdData(void* bfParser, uint8* data, int32 length);
@@ -197,11 +197,11 @@ namespace IDE.Compiler
 			mNativeBfParser = null;
 		}
 
-        public void SetSource(StringView data, String fileName)
+        public void SetSource(StringView data, String fileName, int textVersion)
         {
             Debug.Assert(!mIsUsed);
             mIsUsed = true;
-            BfParser_SetSource(mNativeBfParser, data.Ptr, (int32)data.Length, fileName);
+            BfParser_SetSource(mNativeBfParser, data.Ptr, (int32)data.Length, fileName, (.)textVersion);
         }
 
         public void SetCharIdData(ref IdSpan char8IdData)

+ 10 - 3
IDE/src/Compiler/BfPassInstance.bf

@@ -31,7 +31,7 @@ namespace IDE.Compiler
 
         [CallingConvention(.Stdcall), CLink]
         static extern char8* BfPassInstance_GetErrorData(void* mNativeResolvePassData, int32 errorIdx, out int32 code, out bool isWarning,
-            out bool isAfter, out bool isDeferred, out bool isWhileSpecializing, out bool isPersistent, out char8* projectName,
+            out bool isAfter, out bool isDeferred, out int8 isWhileSpecializing, out bool isPersistent, out char8* projectName,
 			out char8* fileName, out int32 srcStart, out int32 srcEnd, int32* srcLine, int32* srcColumn, out int32 moreInfoCount);
 
 		[CallingConvention(.Stdcall), CLink]
@@ -42,11 +42,18 @@ namespace IDE.Compiler
 
         public class BfError
         {
+			public enum SpecializingKind
+			{
+				None,
+				Type,
+				Method
+			}
+
             public bool mIsWarning;
 			public int32 mCode;
             public bool mIsAfter;
             public bool mIsDeferred;
-            public bool mIsWhileSpecializing;
+            public SpecializingKind mWhileSpecializing;
             public bool mIsPersistent;
 			public String mProject ~ delete _;
             public String mError ~ delete _;
@@ -127,7 +134,7 @@ namespace IDE.Compiler
 			char8* projectName = null;
 			char8* fileName = null;
             bfError.mError = new String(BfPassInstance_GetErrorData(mNativeBfPassInstance, errorIdx, out bfError.mCode, out bfError.mIsWarning, out bfError.mIsAfter, out bfError.mIsDeferred, 
-                out bfError.mIsWhileSpecializing, out bfError.mIsPersistent, out projectName, out fileName, out bfError.mSrcStart, out bfError.mSrcEnd,
+                out *(int8*)&bfError.mWhileSpecializing, out bfError.mIsPersistent, out projectName, out fileName, out bfError.mSrcStart, out bfError.mSrcEnd,
 				getLine ? &bfError.mLine : null, getLine ? &bfError.mColumn : null,
 				out bfError.mMoreInfoCount));
 			if (projectName != null)

+ 2 - 2
IDE/src/IDEApp.bf

@@ -5725,7 +5725,7 @@ namespace IDE
 				internalDebugMenu.AddMenuItem("Error Test", null, new (menu) => { DoErrorTest(); } );
 				internalDebugMenu.AddMenuItem("Reconnect BeefPerf", null, new (menu) => { BeefPerf.RetryConnect(); } );
 	            AddMenuItem(internalDebugMenu, "Report Memory", "Report Memory");
-				internalDebugMenu.AddMenuItem("Crash", null, new (menu) => { Runtime.FatalError("Bad"); });
+				internalDebugMenu.AddMenuItem("Crash", null, new (menu) => { int* ptr = null; *ptr = 123; });
 				internalDebugMenu.AddMenuItem("Show Welcome", null, new (menu) => { ShowWelcome(); });
 				internalDebugMenu.AddMenuItem("Exit Test", null, new (menu) => { ExitTest(); });
 				internalDebugMenu.AddMenuItem("Run Test", null, new (menu) => { mRunTest = !mRunTest; });
@@ -8969,7 +8969,7 @@ namespace IDE
             mFileWatcher.FileIsValid(fullPath);
 
             var bfParser = bfSystem.CreateParser(projectSource);
-            bfParser.SetSource(data, fullPath);
+            bfParser.SetSource(data, fullPath, -1);
             worked &= bfParser.Parse(passInstance, false);
             worked &= bfParser.Reduce(passInstance);
             worked &= bfParser.BuildDefs(passInstance, null, false);

+ 1 - 1
IDE/src/ui/DisassemblyPanel.bf

@@ -331,7 +331,7 @@ namespace IDE.ui
 	                var passInstance = bfSystem.CreatePassInstance();
 	            
 					parser.SetIsClassifying();
-	                parser.SetSource(text, useFileName);	                
+	                parser.SetSource(text, useFileName, -1);	                
 	                parser.Parse(passInstance, !isBeefSource);
 	                if (isBeefSource)
 	                    parser.Reduce(passInstance);

+ 104 - 16
IDE/src/ui/SourceEditWidgetContent.bf

@@ -217,6 +217,7 @@ namespace IDE.ui
 				public Monitor mMonitor = new .() ~ delete _;
 				public WorkState mTypeWorkState;
 				public bool mAwaitingLoad;
+				public bool mEmitRemoved;
 				bool mIgnoreChange = false;
 
 				public this(EmitEmbed emitEmbed)
@@ -263,6 +264,11 @@ namespace IDE.ui
 					}
 				}
 
+				public ~this()
+				{
+
+				}
+
 				private void GenericTypeEditChanged(EditEvent theEvent)
 				{
 					if (mIgnoreChange)
@@ -376,16 +382,19 @@ namespace IDE.ui
 					}
 
 					mAwaitingLoad = false;
-					for (var explicitTypeName in mEmitEmbed.mEditWidgetContent.mSourceViewPanel.[Friend]mExplicitEmitTypes)
+					if (!mEmitRemoved)
 					{
-						if ((IDEUtils.GenericEquals(mTypeName, explicitTypeName)) && (mTypeName != explicitTypeName))
+						for (var explicitTypeName in mEmitEmbed.mEditWidgetContent.mSourceViewPanel.[Friend]mExplicitEmitTypes)
+						{
+							if ((IDEUtils.GenericEquals(mTypeName, explicitTypeName)) && (mTypeName != explicitTypeName))
+								mAwaitingLoad = true;
+						}
+
+						var ewc = (SourceEditWidgetContent)mSourceViewPanel.mEditWidget.mEditWidgetContent;
+						if ((ewc.mLineRange.GetValueOrDefault().Length != 0) && (mSourceViewPanel.mEditWidget.mEditWidgetContent.mData.mTextLength == 0))
 							mAwaitingLoad = true;
 					}
 
-					var ewc = (SourceEditWidgetContent)mSourceViewPanel.mEditWidget.mEditWidgetContent;
-					if ((ewc.mLineRange.GetValueOrDefault().Length != 0) && (mSourceViewPanel.mEditWidget.mEditWidgetContent.mData.mTextLength == 0))
-						mAwaitingLoad = true;
-
 					if ((mAwaitingLoad) && (gApp.mUpdateCnt % 4 == 0))
 						MarkDirty();
 				}
@@ -415,7 +424,7 @@ namespace IDE.ui
 				{
 					base.DrawAll(g);
 
-					if (mAwaitingLoad)
+					if (mAwaitingLoad || mEmitRemoved)
 					{
 						var rect = mSourceViewPanel.mEditWidget.GetRect();
 						mSourceViewPanel.mEditWidget.SelfToOtherTranslate(this, 0, 0, out rect.mX, out rect.mY);
@@ -424,7 +433,9 @@ namespace IDE.ui
 						{
 							g.FillRect(rect.mX, rect.mY, rect.mWidth, rect.mHeight);
 						}
-						IDEUtils.DrawWait(g, rect.mX + rect.mWidth / 2, rect.mY + rect.mHeight / 2, mUpdateCnt);
+
+						if (mAwaitingLoad)
+							IDEUtils.DrawWait(g, rect.mX + rect.mWidth / 2, rect.mY + rect.mHeight / 2, mUpdateCnt);
 					}
 				}
 
@@ -615,6 +626,7 @@ namespace IDE.ui
 			public int32 mCollapseTextVersionId;
 			public List<CollapseData> mCollapseData = new .() ~ delete _;
 			public List<EmitData> mEmitData = new .() ~ delete _;
+			public Dictionary<String, int32> mHasFailedEmitSet = new .() ~ delete _;
 			public List<String> mTypeNames = new .() ~ DeleteContainerAndItems!(_);
 
 			public void Clear()
@@ -625,7 +637,6 @@ namespace IDE.ui
 
 			public void ClearCollapse()
 			{
-
 				mCollapseData.Clear();
 			}
 
@@ -633,6 +644,7 @@ namespace IDE.ui
 			{
 				mEmitData.Clear();
 				ClearAndDeleteItems(mTypeNames);
+				mHasFailedEmitSet.Clear();
 			}
 
 			public ~this()
@@ -4763,7 +4775,7 @@ namespace IDE.ui
 										defer:: delete parser;
 	                                    var text = scope String();
 	                                    mEditWidget.GetText(text);
-	                                    parser.SetSource(text, mSourceViewPanel.mFilePath);
+	                                    parser.SetSource(text, mSourceViewPanel.mFilePath, -1);
 	                                    parser.SetAutocomplete(textIdx);
 	                                    passInstance = bfSystem.CreatePassInstance();
 	                                    parser.Parse(passInstance, !mSourceViewPanel.mIsBeefSource);
@@ -5631,9 +5643,24 @@ namespace IDE.ui
 								emitEmbed.mView.MinHeight, emitEmbed.mView.MaxAutoHeight);
 						}
 
+						//float prevPhysHeight = emitEmbed.mView.mHeight;
+
 						float height = emitEmbed.mView.mWantHeight * emitEmbed.mOpenPct;
 						emitEmbed.mView.SizeTo(GS!(0), (float)curY + lineHeight, mParent.mWidth, height);
 						lineHeight += height;
+
+						/*float physHeightChange = emitEmbed.mView.mHeight - prevPhysHeight;
+						if (physHeightChange != 0)
+						{
+							bool isCursorAfter = false;
+							if (mVirtualCursorPos != null)
+								isCursorAfter = mVirtualCursorPos.Value.mLine > line;
+							else
+								isCursorAfter = mCursorTextPos >= data.mLineStarts[line + 1];
+
+							if (isCursorAfter)
+								mEditWidget.VertScrollTo(mEditWidget.mVertPos.mDest + physHeightChange);
+						}*/
 					}
 				}
 
@@ -5706,9 +5733,14 @@ namespace IDE.ui
 
 			if (data.mCollapseParseRevision != mCollapseParseRevision)
 			{
+				//Debug.WriteLine($"GetTextData NewCollapseParseRevision:{data.mCollapseParseRevision} OldCollapseParseRevision:{mCollapseParseRevision}");
+
 				mCollapseParseRevision = data.mCollapseParseRevision;
 				mCollapseTextVersionId = data.mCollapseTextVersionId;
-				mCollapseTypeNames.ClearAndDeleteItems();
+				List<String> prevTypeNames = scope .()..AddRange(mCollapseTypeNames);
+				defer prevTypeNames.ClearAndDeleteItems();
+
+				mCollapseTypeNames.Clear();
 				for (var name in data.mTypeNames)
 					mCollapseTypeNames.Add(new .(name));
 
@@ -5718,6 +5750,8 @@ namespace IDE.ui
 					if (var emitEmbed = embed as SourceEditWidgetContent.EmitEmbed)
 					{
 						emitEmbedMap[emitEmbed.mAnchorId] = emitEmbed;
+
+						//Debug.WriteLine($" mEmbed {embed} AnchorId:{emitEmbed.mAnchorId}");
 					}
 				}
 
@@ -5730,9 +5764,21 @@ namespace IDE.ui
 					{
 						if (line != emitEmbed.mLine)
 						{
-						   	mEmbeds.Remove(emitEmbed.mLine);
+							//Debug.WriteLine($" Moving {emitEmbed} from {emitEmbed.mLine} to {line}");
+
+							mEmbeds.Remove(emitEmbed.mLine);
 							emitEmbed.mLine = (.)line;
-							mEmbeds[(.)line] = emitEmbed;
+
+							if (mEmbeds.TryAdd((.)line, var keyPtr, var valuePtr))
+							{
+								*valuePtr = emitEmbed;
+							}
+							else
+							{
+								//Debug.WriteLine($"  Occupied- deleting {emitEmbed}");
+								delete emitEmbed;
+								emitEmbed = null;
+							}
 						}
 					}
 					else if (mEmbeds.TryAdd((.)line, var keyPtr, var valuePtr))
@@ -5755,6 +5801,7 @@ namespace IDE.ui
 					
 					if (emitEmbed.mView != null)
 					{
+						emitEmbed.mView.mEmitRemoved = false;
 						Range range = .(emitData.mStartLine, emitData.mEndLine);
 						var ew = emitEmbed.mView.mSourceViewPanel.mEditWidget;
 						var ewc = ew.mEditWidgetContent as DarkEditWidgetContent;
@@ -5774,9 +5821,24 @@ namespace IDE.ui
 
 				for (var emitEmbed in emitEmbedMap.Values)
 				{
-					mCollapseNeedsUpdate = true;
-					mEmbeds.Remove(emitEmbed.mLine);
-					delete emitEmbed;
+					//Debug.WriteLine($" Deleting(1) {emitEmbed}");
+
+					int32 typeNameIdx = -1;
+					if (emitEmbed.mView != null)
+						if (!data.mHasFailedEmitSet.TryGet(emitEmbed.mTypeName, ?, out typeNameIdx))
+							typeNameIdx = -1;
+
+					if (typeNameIdx != -1)
+					{
+						emitEmbed.mTypeName = mCollapseTypeNames[typeNameIdx];
+						emitEmbed.mView.mEmitRemoved = true;
+					}
+					else
+					{
+						mCollapseNeedsUpdate = true;
+						mEmbeds.Remove(emitEmbed.mLine);
+						delete emitEmbed;
+					}
 				}
 
 				for (var collapseData in ref data.mCollapseData)
@@ -5798,6 +5860,7 @@ namespace IDE.ui
 					{
 						if (mEmbeds.GetAndRemove(entry.mAnchorLine) case .Ok(let val))
 						{
+							//Debug.WriteLine($" Deleting(2) {val.value}");
 							delete val.value;
 						}
 						@entry.Remove();
@@ -5820,6 +5883,7 @@ namespace IDE.ui
 					{
 						if (mEmbeds.GetAndRemove(entry.mAnchorIdx) case .Ok(let val))
 						{
+							//Debug.WriteLine($" Removing {val.value}");
 							if (val.value is CollapseSummary)
 								delete val.value;
 						}
@@ -5837,13 +5901,18 @@ namespace IDE.ui
 					
 						if (mEmbeds.TryAdd(entry.mAnchorLine, var keyPtr, var valuePtr))
 						{
+							//Debug.WriteLine($" Moving {val} to line {entry.mAnchorLine}");
+
 							if (var collapseSummary = val as SourceEditWidgetContent.CollapseSummary)
 								collapseSummary.mCollapseIndex = (.)@entry.Index;
 							val.mLine = entry.mAnchorLine;
 							*valuePtr = val;
 						}
 						else
+						{
+							//Debug.WriteLine($" Deleting(3) {val}");
 							delete val;
+						}
 					}
 				}
 
@@ -6202,6 +6271,8 @@ namespace IDE.ui
 
 		public void RefreshCollapseRegion(SourceEditWidgetContent.CollapseEntry* entry, int32 prevAnchorLine, bool failed)
 		{
+			//Debug.WriteLine($"RefreshCollapseRegion PrevLine:{prevAnchorLine} NewLine:{entry.mAnchorLine}");
+
 			if (failed)
 			{
 				if (mEmbeds.GetAndRemove(prevAnchorLine) case .Ok(let val))
@@ -6213,13 +6284,18 @@ namespace IDE.ui
 			{
 				if (mEmbeds.GetAndRemove(prevAnchorLine) case .Ok(let val))
 				{
+					//Debug.WriteLine($" Moving {val.value} from line {prevAnchorLine} to line {entry.mAnchorLine}");
+
 					if (mEmbeds.TryAdd(entry.mAnchorLine, var keyPtr, var valuePtr))
 					{
 						val.value.mLine = entry.mAnchorLine;
 						*valuePtr = val.value;
 					}
 					else
+					{
+						//Debug.WriteLine($"  Occupied- deleting {val}");
 						delete val.value;
+					}
 				}
 			}
 		}
@@ -6329,6 +6405,8 @@ namespace IDE.ui
 				data.ClearCollapse();
 			}
 
+			//Debug.WriteLine($"ParseCollapseRegions {resolveType} CollapseRevision:{data.mCollapseParseRevision+1} TextVersion:{textVersion} IdSpan:{idSpan:D}");
+
 			List<int32> typeNameIdxMap = scope .();
 			Dictionary<StringView, int32> typeNameMap = scope .();
 			Dictionary<int32, int32> emitAnchorIds = scope .();
@@ -6399,12 +6477,21 @@ namespace IDE.ui
 					emitData.mStartLine = int32.Parse(itr.GetNext().Value);
 					emitData.mEndLine = int32.Parse(itr.GetNext().Value);
 					emitData.mAnchorId = lookupCtx.GetIdAtIndex(emitData.mAnchorIdx);
+					//var foundTextVersion = int32.Parse(itr.GetNext().Value).Value;
 					emitData.mOnlyInResolveAll = resolveType == .None;
 					emitData.mIncludedInClassify = resolveType != .None;
 					emitData.mIncludedInResolveAll = resolveType == .None;
 
+					if (emitData.mAnchorIdx == -1)
+					{
+						data.mHasFailedEmitSet[data.mTypeNames[emitData.mTypeNameIdx]] = emitData.mTypeNameIdx;
+						continue;
+					}
+
 					if (emitAnchorIds.TryGetValue(emitData.mAnchorId, var idx))
 					{
+						//Debug.WriteLine($" Found emit AnchorIdx:{emitData.mAnchorIdx} AnchorId:{emitData.mAnchorId} CurTextVersion:{textVersion} FoundTextVersion:{foundTextVersion}");
+
 						var curEmitData = ref data.mEmitData[idx];
 
 						if (resolveType == .None)
@@ -6420,6 +6507,7 @@ namespace IDE.ui
 						continue;
 					}
 
+					//Debug.WriteLine($" New emit AnchorIdx:{emitData.mAnchorIdx} AnchorId:{emitData.mAnchorId} CurTextVersion:{textVersion} FoundTextVersion:{foundTextVersion}");
 					data.mEmitData.Add(emitData);
 					continue;
 				}

+ 51 - 12
IDE/src/ui/SourceViewPanel.bf

@@ -392,6 +392,17 @@ namespace IDE.ui
 			SkipResult
         }
 
+		struct ParsedState
+		{
+			public IdSpan mIdSpan;
+			public int32 mTextVersion = -1;
+
+			public void Dispose() mut
+			{
+				mIdSpan.Dispose();
+			}
+		}
+
 		public bool mAsyncAutocomplete = true;
 
         public SourceEditWidget mEditWidget;        
@@ -426,6 +437,7 @@ namespace IDE.ui
         bool mWantsFullClassify; // This triggers a classify
         bool mWantsFullRefresh; // If mWantsFullClassify is set, mWantsFullRefresh makes the whole thing refresh
 		bool mWantsCollapseRefresh;
+		ParsedState mParsedState ~ _.Dispose(); // The current data the resolver is using from this file
 		bool mRefireMouseOverAfterRefresh;
         bool mWantsBackgroundAutocomplete;
 		bool mSkipFastClassify;
@@ -1463,14 +1475,18 @@ namespace IDE.ui
 			defer delete resolvePassData;
 
 			bfSystem.Lock(0);
+
 			var collapseData = bfCompiler.GetCollapseRegions(parser, resolvePassData, explicitEmitTypeNames, .. scope .());
+
 			using (mMonitor.Enter())
 			{
 				DeleteAndNullify!(mQueuedCollapseData);
 				mQueuedCollapseData = new .();
 				mQueuedCollapseData.mData.Set(collapseData);
 				mQueuedCollapseData.mTextVersion = textVersion;
-				mQueuedCollapseData.mCharIdSpan = charIdSpan;
+				mQueuedCollapseData.mCharIdSpan = charIdSpan.Duplicate();
+
+				//Debug.WriteLine($"DoRefreshCollapse finished TextVersion:{textVersion} IdSpan:{charIdSpan:D}");
 			}
 			bfSystem.Unlock();
 		}
@@ -1530,7 +1546,7 @@ namespace IDE.ui
 			defer delete resolvePassData;
             var passInstance = bfSystem.CreatePassInstance("DoFastClassify");
 			defer delete passInstance;
-            parser.SetSource(text, mFilePath);
+            parser.SetSource(text, mFilePath, -1);
             parser.SetIsClassifying();
             parser.Parse(passInstance, !mIsBeefSource);
             if (mIsBeefSource)
@@ -1582,7 +1598,7 @@ namespace IDE.ui
 			defer delete resolvePassData;
 		    var passInstance = bfSystem.CreatePassInstance("DoFastClassify");
 			defer delete passInstance;
-		    parser.SetSource(text, mFilePath);
+		    parser.SetSource(text, mFilePath, -1);
 		    parser.SetIsClassifying();
 		    parser.Parse(passInstance, !mIsBeefSource);
 		    if (mIsBeefSource)
@@ -1929,6 +1945,14 @@ namespace IDE.ui
 			if ((resolveType == .Classify) || (resolveType == .ClassifyFullRefresh))
 				gApp.mErrorsPanel.SetNeedsResolveAll();
 
+			if ((resolveType.IsClassify) && (!resolveParams.mCharIdSpan.IsEmpty))
+			{
+				//Debug.WriteLine($"DoClassify {resolveType} TextVersion:{resolveParams.mTextVersion} IdSpan:{resolveParams.mCharIdSpan:D}");
+
+				mParsedState.mIdSpan.DuplicateFrom(ref resolveParams.mCharIdSpan);
+				mParsedState.mTextVersion = resolveParams.mTextVersion;
+			}
+
 			/*if (resolveType == .Autocomplete)
 			{
 				Thread.Sleep(250);
@@ -2050,14 +2074,18 @@ namespace IDE.ui
                 charData[i].mDisplayPassId = (int32)SourceDisplayId.Cleared;
                 chars[i] = (char8)charData[i].mChar;
             }
-                
+
+			int textVersion = -1;
+			if (resolveParams != null)
+				textVersion = resolveParams.mTextVersion;
+
             if (!isBackground)
             {
                 bfSystem.PerfZoneEnd();
                 bfSystem.PerfZoneStart("SetSource");
             }
 			parser.SetIsClassifying();
-            parser.SetSource(.(chars, charLen), mFilePath);
+            parser.SetSource(.(chars, charLen), mFilePath, textVersion);
             if (!isBackground)
             {
                 bfSystem.PerfZoneEnd();
@@ -5045,7 +5073,7 @@ namespace IDE.ui
 			defer delete parser;
             var text = scope String();
             mEditWidget.GetText(text);
-            parser.SetSource(text, mFilePath);
+            parser.SetSource(text, mFilePath, -1);
             var passInstance = bfSystem.CreatePassInstance();
 			defer delete passInstance;
             parser.Parse(passInstance, false);
@@ -5252,7 +5280,7 @@ namespace IDE.ui
 
 			var text = scope String();
 			mEditWidget.GetText(text);
-			parser.SetSource(text, mFilePath);
+			parser.SetSource(text, mFilePath, -1);
 			parser.SetAutocomplete(textIdx);
 			let passInstance = bfSystem.CreatePassInstance("Mouseover");
 			parser.SetCompleteParse();
@@ -5321,7 +5349,7 @@ namespace IDE.ui
 					
 	                    var text = scope String();
 	                    mEditWidget.GetText(text);
-	                    parser.SetSource(text, mFilePath);
+	                    parser.SetSource(text, mFilePath, -1);
 	                    parser.SetAutocomplete(textIdx);
 	                    passInstance = bfSystem.CreatePassInstance("Mouseover");
 						parser.SetCompleteParse();
@@ -5643,8 +5671,10 @@ namespace IDE.ui
 
 	                    for (var bfError in mErrorList)
 	                    {
-	                        if (bfError.mIsWhileSpecializing)
+							if ((bfError.mWhileSpecializing.HasFlag(.Type)) && (mEmbedKind == .None))
 	                            continue;
+							if ((bfError.mWhileSpecializing.HasFlag(.Method)) && (mEmbedKind != .Method))
+								continue;
 
 	                        if ((textIdx >= bfError.mSrcStart) && (textIdx < bfError.mSrcEnd))
 	                        {
@@ -6515,9 +6545,16 @@ namespace IDE.ui
 								break;
 
 							var data = mEditWidget.mEditWidgetContent.mData;
+							if (mParsedState.mTextVersion == -1)
+							{
+								mParsedState.mIdSpan.DuplicateFrom(ref data.mTextIdData);
+								mParsedState.mTextVersion = data.mCurTextVersionId;
+							}
+
+							//Debug.WriteLine($"Queueing DoRefreshCollapse TextVersion:{mParsedState.mTextVersion} IdSpan:{mParsedState.mIdSpan:D}");
 							compiler.DoBackground(new () =>
 								{
-									DoRefreshCollapse(bfParser, data.mCurTextVersionId, data.mTextIdData.Duplicate());
+									DoRefreshCollapse(bfParser, mParsedState.mTextVersion, mParsedState.mIdSpan);
 								});
 						}
 					}
@@ -6959,8 +6996,10 @@ namespace IDE.ui
                     int srcStart = bfError.mSrcStart;
                     int srcEnd = bfError.mSrcEnd;
 
-                    if (bfError.mIsWhileSpecializing)
-                        continue;
+                    if ((bfError.mWhileSpecializing.HasFlag(.Type)) && (mEmbedKind == .None))
+					    continue;
+					if ((bfError.mWhileSpecializing.HasFlag(.Method)) && (mEmbedKind != .Method))
+						continue;
 
 					if ((bfError.mIsDeferred) && (hadNonDeferredErrors))
 						continue;

+ 7 - 5
IDEHelper/Compiler/BfCompiler.cpp

@@ -9919,7 +9919,7 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetCollapseRegions(BfCompiler* bfCo
 				*valuePtr = foundTypeIds.mCount - 1;
 				outString += "+";
 
-				if (emitParser == NULL)
+				if ((emitParser == NULL) || (!emitParser->mIsEmitted))
 				{
 					String typeName;
 					outString += typeInst->mTypeDef->mProject->mName;
@@ -9989,7 +9989,8 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetCollapseRegions(BfCompiler* bfCo
 
 					int startLine = 0;
 					int startLineChar = 0;
-					emitParser->GetLineCharAtIdx(kv.mValue.mSrcStart, startLine, startLineChar);
+					if (kv.mValue.mSrcStart >= 0)
+						emitParser->GetLineCharAtIdx(kv.mValue.mSrcStart, startLine, startLineChar);
 
 					int srcEnd = kv.mValue.mSrcEnd - 1;
 					while (srcEnd >= kv.mValue.mSrcStart)
@@ -10006,8 +10007,9 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetCollapseRegions(BfCompiler* bfCo
 
 					int endLine = 0;
 					int endLineChar = 0;
-					emitParser->GetLineCharAtIdx(srcEnd, endLine, endLineChar);
-					outString += StrFormat("e%d,%d,%d,%d\n", embedId, charIdx, startLine, endLine + 1);
+					if (srcEnd >= 0)
+						emitParser->GetLineCharAtIdx(srcEnd, endLine, endLineChar);
+					outString += StrFormat("e%d,%d,%d,%d,%d\n", embedId, charIdx, startLine, endLine + 1, typeInst->mTypeDef->mTypeDeclaration->GetParser()->mTextVersion);
 				}
 			}
 
@@ -10036,7 +10038,7 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetCollapseRegions(BfCompiler* bfCo
 							if (embedId == -1)
 								continue;
 
-							outString += StrFormat("e%d,%d,%d,%d\n", embedId, kv.mKey, 0, 0);
+							outString += StrFormat("e%d,%d,%d,%d,%d\n", embedId, kv.mKey, 0, 0, -1);
 						}
 					}
 				};

+ 10 - 9
IDEHelper/Compiler/BfModule.cpp

@@ -2955,7 +2955,7 @@ bool BfModule::IsSkippingExtraResolveChecks()
 	return mCompiler->IsSkippingExtraResolveChecks();
 }
 
-bool BfModule::AddErrorContext(StringImpl& errorString, BfAstNode* refNode, bool& isWhileSpecializing, bool isWarning)
+bool BfModule::AddErrorContext(StringImpl& errorString, BfAstNode* refNode, BfWhileSpecializingFlags& isWhileSpecializing, bool isWarning)
 {
 	bool isWhileSpecializingMethod = false;
 	if ((mIsSpecialModule) && (mModuleName == "vdata"))
@@ -3011,19 +3011,20 @@ bool BfModule::AddErrorContext(StringImpl& errorString, BfAstNode* refNode, bool
 			if (isSpecializedMethod)
 			{
 				errorString += StrFormat("\n  while specializing method '%s'", MethodToString(methodInstance).c_str());
-				isWhileSpecializing = true;
+				isWhileSpecializing = (BfWhileSpecializingFlags)(isWhileSpecializing | BfWhileSpecializingFlag_Method);
 				isWhileSpecializingMethod = true;
 			}
 			else if ((methodInstance != NULL) && (methodInstance->mIsForeignMethodDef))
 			{
 				errorString += StrFormat("\n  while implementing default interface method '%s'", MethodToString(methodInstance).c_str());
-				isWhileSpecializing = true;
+				isWhileSpecializing = (BfWhileSpecializingFlags)(isWhileSpecializing | BfWhileSpecializingFlag_Method);
 				isWhileSpecializingMethod = true;
 			}
-			else if ((mCurTypeInstance->IsGenericTypeInstance()) && (!mCurTypeInstance->IsUnspecializedType()))
+
+			if ((mCurTypeInstance->IsGenericTypeInstance()) && (!mCurTypeInstance->IsUnspecializedType()))
 			{
 				errorString += StrFormat("\n  while specializing type '%s'", TypeToString(mCurTypeInstance).c_str());
-				isWhileSpecializing = true;
+				isWhileSpecializing = (BfWhileSpecializingFlags)(isWhileSpecializing | BfWhileSpecializingFlag_Type);
 			}
 
 			return true;
@@ -3059,7 +3060,7 @@ bool BfModule::AddErrorContext(StringImpl& errorString, BfAstNode* refNode, bool
 	if ((!isWhileSpecializing) && (mCurTypeInstance != NULL) && ((mCurTypeInstance->IsGenericTypeInstance()) && (!mCurTypeInstance->IsUnspecializedType())))
 	{
 		errorString += StrFormat("\n  while specializing type '%s'", TypeToString(mCurTypeInstance).c_str());
-		isWhileSpecializing = true;
+		isWhileSpecializing = (BfWhileSpecializingFlags)(isWhileSpecializing | BfWhileSpecializingFlag_Type);
 	}
 	
 	return true;
@@ -3131,7 +3132,7 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
 	BfLogSysM("BfModule::Fail module %p type %p %s\n", this, mCurTypeInstance, error.c_str());
 	
  	String errorString = error;	
-	bool isWhileSpecializing = false;	
+	BfWhileSpecializingFlags isWhileSpecializing = BfWhileSpecializingFlag_None;
 	if (!AddErrorContext(errorString, refNode, isWhileSpecializing, false))
 		return NULL;
 	
@@ -3276,10 +3277,10 @@ BfError* BfModule::Warn(int warningNum, const StringImpl& warning, BfAstNode* re
 		refNode = BfNodeToNonTemporary(refNode);
 
 	String warningString = warning;
-	bool isWhileSpecializing = false;
+	BfWhileSpecializingFlags isWhileSpecializing = BfWhileSpecializingFlag_None;
 	if (!AddErrorContext(warningString, refNode, isWhileSpecializing, true))
 		return NULL;
-	bool deferWarning = isWhileSpecializing;
+	bool deferWarning = isWhileSpecializing != BfWhileSpecializingFlag_None;
 
 	if ((mCurMethodState != NULL) && (mCurMethodState->mMixinState != NULL))
 	{

+ 1 - 1
IDEHelper/Compiler/BfModule.h

@@ -1558,7 +1558,7 @@ public:
 	void SetFail();
 	void VerifyOnDemandMethods();
 	bool IsSkippingExtraResolveChecks();
-	bool AddErrorContext(StringImpl& errorString, BfAstNode* refNode, bool& isWhileSpecializing, bool isWarning);	
+	bool AddErrorContext(StringImpl& errorString, BfAstNode* refNode, BfWhileSpecializingFlags& isWhileSpecializing, bool isWarning);
 	CeDbgState* GetCeDbgState();
 	BfError* Fail(const StringImpl& error, BfAstNode* refNode = NULL, bool isPersistent = false, bool deferError = false);
 	BfError* FailInternal(const StringImpl& error, BfAstNode* refNode = NULL);

+ 20 - 5
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -2507,7 +2507,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance*
 				if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext == NULL))
 					typeInstance->mCeTypeInfo->mNext = new BfCeTypeInfo();
 				if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext != NULL))
-					typeInstance->mCeTypeInfo->mNext->mFailed = true;
+					typeInstance->mCeTypeInfo->mNext->mFastFinished = true;
 				if (typeInstance->mCeTypeInfo != NULL)
 				{
 					BfCeTypeEmitEntry* entry = NULL;
@@ -2528,6 +2528,8 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance*
 				entry.mEmitData = ceEmitContext->mEmitData;
 				typeInstance->mCeTypeInfo->mNext->mTypeIFaceMap[typeId] = entry;
 			}
+			else if ((ceEmitContext->mFailed) && (typeInstance->mCeTypeInfo != NULL))
+				typeInstance->mCeTypeInfo->mFailed = true;
 
 			if ((ceEmitContext->HasEmissions()) && (!mCompiler->mFastFinish))
 			{
@@ -2787,7 +2789,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
 				if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext == NULL))
 					typeInstance->mCeTypeInfo->mNext = new BfCeTypeInfo();
 				if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext != NULL))
-					typeInstance->mCeTypeInfo->mNext->mFailed = true;
+					typeInstance->mCeTypeInfo->mNext->mFastFinished = true;
 				if (typeInstance->mCeTypeInfo != NULL)
 				{
 					BfCeTypeEmitEntry* entry = NULL;
@@ -2808,6 +2810,8 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
 				entry.mEmitData = ceEmitContext->mEmitData;
 				typeInstance->mCeTypeInfo->mNext->mOnCompileMap[methodDef->mIdx] = entry;
 			}
+			else if ((ceEmitContext->mFailed) && (typeInstance->mCeTypeInfo != NULL))
+				typeInstance->mCeTypeInfo->mFailed = true;
 			
 			if (!ceEmitContext->mEmitData.IsEmpty())
 			{
@@ -4798,6 +4802,8 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 
 			if (typeInstance->mCeTypeInfo != NULL)
 			{
+				bool prevHadEmissions = !typeInstance->mCeTypeInfo->mEmitSourceMap.IsEmpty();
+
 				if (typeInstance->mCeTypeInfo->mNext != NULL)
 				{
 					BfLogSysM("Type %p injecting next ceTypeInfo %p into ceTypeInfo %p\n", typeInstance, typeInstance->mCeTypeInfo->mNext, typeInstance->mCeTypeInfo);
@@ -4828,16 +4834,16 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 
 					typeInstance->mCeTypeInfo->mNext->mHash = hashCtx.Finish128();
 
-					if (!typeInstance->mCeTypeInfo->mNext->mFailed)
+					if (!typeInstance->mCeTypeInfo->mNext->mFastFinished)
 					{
 						if ((typeInstance->mCeTypeInfo->mHash != typeInstance->mCeTypeInfo->mNext->mHash) && (!typeInstance->mCeTypeInfo->mHash.IsZero()))
 							mContext->QueueMidCompileRebuildDependentTypes(typeInstance, "comptime hash changed");
 						typeInstance->mCeTypeInfo->mEmitSourceMap = typeInstance->mCeTypeInfo->mNext->mEmitSourceMap;
 						typeInstance->mCeTypeInfo->mOnCompileMap = typeInstance->mCeTypeInfo->mNext->mOnCompileMap;
 						typeInstance->mCeTypeInfo->mTypeIFaceMap = typeInstance->mCeTypeInfo->mNext->mTypeIFaceMap;
-						typeInstance->mCeTypeInfo->mHash = typeInstance->mCeTypeInfo->mNext->mHash;						
+						typeInstance->mCeTypeInfo->mHash = typeInstance->mCeTypeInfo->mNext->mHash;
 					}
-					
+										
 					delete typeInstance->mCeTypeInfo->mNext;
 					typeInstance->mCeTypeInfo->mNext = NULL;
 				}
@@ -4851,6 +4857,15 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 					typeInstance->mCeTypeInfo->mTypeIFaceMap.Clear();
 					typeInstance->mCeTypeInfo->mHash = Val128();
 				}
+
+				if ((typeInstance->mCeTypeInfo->mFailed) &&
+					(prevHadEmissions) &&
+					(typeInstance->mCeTypeInfo->mEmitSourceMap.IsEmpty()))
+				{
+					// Just add a marker to retain the previous open emits
+					typeInstance->mCeTypeInfo->mEmitSourceMap[-1] = BfCeTypeEmitSource();
+				}
+				typeInstance->mCeTypeInfo->mFailed = false;
 			}
 
 			if ((typeInstance->mCeTypeInfo != NULL) && (!typeInstance->mCeTypeInfo->mPendingInterfaces.IsEmpty()))

+ 3 - 1
IDEHelper/Compiler/BfParser.cpp

@@ -345,6 +345,7 @@ BfParser::BfParser(BfSystem* bfSystem, BfProject* bfProject) : BfSource(bfSystem
 
 	gParserCount++;	
 
+	mTextVersion = -1;
 	mEmbedKind = BfSourceEmbedKind_None;
 	mUsingCache = false;
 	mParserData = NULL;
@@ -3850,9 +3851,10 @@ static BfAstNode* FindDebugExpressionNode(BfAstNode* checkNode, int cursorIdx)
 
 //////////////////////////////////////////////////////////////////////////
 
-BF_EXPORT void BF_CALLTYPE BfParser_SetSource(BfParser* bfParser, const char* data, int length, const char* fileName)
+BF_EXPORT void BF_CALLTYPE BfParser_SetSource(BfParser* bfParser, const char* data, int length, const char* fileName, int textVersion)
 {
 	bfParser->mFileName = fileName;
+	bfParser->mTextVersion = textVersion;
 	bfParser->SetSource(data, length);
 }
 

+ 1 - 0
IDEHelper/Compiler/BfParser.h

@@ -160,6 +160,7 @@ public:
 	BfPassInstance* mPassInstance;
 	BfSourceClassifier* mSourceClassifier;
 	String mFileName;	
+	int mTextVersion;
 	BfSourceEmbedKind mEmbedKind;
 	bool mAwaitingDelete;	
 	

+ 1 - 1
IDEHelper/Compiler/BfSystem.cpp

@@ -4102,7 +4102,7 @@ BF_EXPORT int BF_CALLTYPE BfPassInstance_GetErrorCount(BfPassInstance* bfPassIns
 	return (int)bfPassInstance->mErrors.size();
 }
 
-BF_EXPORT const char* BF_CALLTYPE BfPassInstance_GetErrorData(BfPassInstance* bfPassInstance, int errorIdx, int& outCode, bool& outIsWarning, bool& outIsAfter, bool& outIsDeferred, bool& outIsWhileSpecializing, bool& outIsPersistent, 
+BF_EXPORT const char* BF_CALLTYPE BfPassInstance_GetErrorData(BfPassInstance* bfPassInstance, int errorIdx, int& outCode, bool& outIsWarning, bool& outIsAfter, bool& outIsDeferred, BfWhileSpecializingFlags& outIsWhileSpecializing, bool& outIsPersistent,
 	char*& projectName, char*& fileName, int& outSrcStart, int& outSrcEnd, int* outLine, int* outColumn, int& outMoreInfoCount)
 {
 	BfError* bfError = bfPassInstance->mErrors[errorIdx];

+ 10 - 3
IDEHelper/Compiler/BfSystem.h

@@ -166,6 +166,13 @@ struct BfAtomCompositeEquals
 	}
 };
 
+enum BfWhileSpecializingFlags : int8
+{
+	BfWhileSpecializingFlag_None = 0,
+	BfWhileSpecializingFlag_Type = 1,
+	BfWhileSpecializingFlag_Method = 2
+};
+
 enum BfCompilerOptionFlags
 {
 	BfCompilerOptionFlag_EmitDebugInfo = 1,
@@ -1480,7 +1487,7 @@ class BfError : public BfErrorBase
 public:	
 	bool mIsAfter;	
 	bool mIsPersistent;
-	bool mIsWhileSpecializing;
+	BfWhileSpecializingFlags mIsWhileSpecializing;
 	bool mIgnore;	
 	BfProject* mProject;
 	String mError;
@@ -1489,10 +1496,10 @@ public:
 
 public:
 	BfError()
-	{				
+	{
 		mIsAfter = false;		
 		mIsPersistent = false;
-		mIsWhileSpecializing = false;
+		mIsWhileSpecializing = BfWhileSpecializingFlag_None;
 		mIgnore = false;		
 		mProject = NULL;
 		mWarningNumber = 0;

+ 2 - 0
IDEHelper/Compiler/CeMachine.h

@@ -1011,6 +1011,7 @@ public:
 	Array<int> mPendingInterfaces;
 	Dictionary<CeRebuildKey, CeRebuildValue> mRebuildMap;
 	Val128 mHash;
+	bool mFastFinished;
 	bool mFailed;
 	bool mMayHaveUniqueEmitLocations;
 	BfCeTypeInfo* mNext;
@@ -1018,6 +1019,7 @@ public:
 public:
 	BfCeTypeInfo()
 	{
+		mFastFinished = false;
 		mFailed = false;
 		mMayHaveUniqueEmitLocations = false;
 		mNext = NULL;