ソースを参照

Show comptime emits as embedded sourceviews

Brian Fiete 3 年 前
コミット
4d1e14a1c3
65 ファイル変更3229 行追加616 行削除
  1. 22 13
      BeefLibs/Beefy2D/src/theme/dark/DarkComboBox.bf
  2. 41 5
      BeefLibs/Beefy2D/src/theme/dark/DarkEditWidget.bf
  3. 2 2
      BeefLibs/Beefy2D/src/theme/dark/DarkScrollbar.bf
  4. 10 8
      BeefLibs/Beefy2D/src/widgets/EditWidget.bf
  5. 10 2
      BeefLibs/Beefy2D/src/widgets/ScrollableWidget.bf
  6. 14 3
      BeefLibs/Beefy2D/src/widgets/Scrollbar.bf
  7. 23 0
      BeefLibs/Beefy2D/src/widgets/Widget.bf
  8. 4 0
      BeefySysLib/BeefySysLib.vcxproj
  9. 15 0
      BeefySysLib/BeefySysLib.vcxproj.filters
  10. 4 0
      BeefySysLib/BeefySysLib_static.vcxproj
  11. 15 0
      BeefySysLib/BeefySysLib_static.vcxproj.filters
  12. 4 2
      BeefySysLib/Common.cpp
  13. 110 0
      BeefySysLib/util/ZipFile.cpp
  14. 30 0
      BeefySysLib/util/ZipFile.h
  15. 11 0
      IDE/src/BuildContext.bf
  16. 43 8
      IDE/src/Compiler/BfCompiler.bf
  17. 67 23
      IDE/src/Compiler/BfParser.bf
  18. 17 0
      IDE/src/Compiler/BfResolvePassData.bf
  19. 29 1
      IDE/src/Debugger/DebugManager.bf
  20. 199 59
      IDE/src/IDEApp.bf
  21. 42 0
      IDE/src/IDEUtils.bf
  22. 1 0
      IDE/src/TestManager.bf
  23. 7 0
      IDE/src/Workspace.bf
  24. 2 1
      IDE/src/ui/ErrorsPanel.bf
  25. 5 1
      IDE/src/ui/OutputWidget.bf
  26. 0 4
      IDE/src/ui/QuickFind.bf
  27. 43 13
      IDE/src/ui/RenameSymbolDialog.bf
  28. 651 30
      IDE/src/ui/SourceEditWidgetContent.bf
  29. 488 118
      IDE/src/ui/SourceViewPanel.bf
  30. 2 0
      IDE/src/ui/StatusBar.bf
  31. 81 5
      IDEHelper/COFF.cpp
  32. 4 0
      IDEHelper/COFF.h
  33. 39 25
      IDEHelper/Compiler/BfAutoComplete.cpp
  34. 1 0
      IDEHelper/Compiler/BfAutoComplete.h
  35. 499 118
      IDEHelper/Compiler/BfCompiler.cpp
  36. 4 0
      IDEHelper/Compiler/BfCompiler.h
  37. 20 12
      IDEHelper/Compiler/BfContext.cpp
  38. 2 0
      IDEHelper/Compiler/BfContext.h
  39. 20 9
      IDEHelper/Compiler/BfDefBuilder.cpp
  40. 10 6
      IDEHelper/Compiler/BfExprEvaluator.cpp
  41. 45 32
      IDEHelper/Compiler/BfModule.cpp
  42. 3 2
      IDEHelper/Compiler/BfModule.h
  43. 212 72
      IDEHelper/Compiler/BfModuleTypeUtils.cpp
  44. 58 3
      IDEHelper/Compiler/BfParser.cpp
  45. 11 1
      IDEHelper/Compiler/BfParser.h
  46. 55 2
      IDEHelper/Compiler/BfReducer.cpp
  47. 34 2
      IDEHelper/Compiler/BfResolvePass.cpp
  48. 27 3
      IDEHelper/Compiler/BfResolvePass.h
  49. 2 7
      IDEHelper/Compiler/BfResolvedTypeUtils.h
  50. 44 2
      IDEHelper/Compiler/BfSystem.cpp
  51. 6 5
      IDEHelper/Compiler/BfSystem.h
  52. 21 0
      IDEHelper/Compiler/BfUtil.cpp
  53. 2 0
      IDEHelper/Compiler/BfUtil.h
  54. 6 1
      IDEHelper/Compiler/CeDebugger.cpp
  55. 1 0
      IDEHelper/Compiler/CeDebugger.h
  56. 31 0
      IDEHelper/Compiler/CeMachine.h
  57. 4 0
      IDEHelper/DbgModule.cpp
  58. 2 0
      IDEHelper/DbgModule.h
  59. 13 0
      IDEHelper/DebugManager.cpp
  60. 10 4
      IDEHelper/DebugTarget.cpp
  61. 5 7
      IDEHelper/DebugTarget.h
  62. 2 1
      IDEHelper/Debugger.h
  63. 1 1
      IDEHelper/MiniDumpDebugger.cpp
  64. 41 2
      IDEHelper/WinDebugger.cpp
  65. 2 1
      IDEHelper/WinDebugger.h

+ 22 - 13
BeefLibs/Beefy2D/src/theme/dark/DarkComboBox.bf

@@ -59,7 +59,7 @@ namespace Beefy.theme.dark
         public uint32 mBkgColor;
         public DarkEditWidget mEditWidget;
 		bool mAllowReverseDropdown; // Allow popdown to "popup" if there isn't enough space
-		public Widget mPrevFocusWidget;
+		public SafeWidgetRef mPrevFocusWidget ~ delete _;
 		public bool mFocusDropdown = true;
 		
 		virtual public StringView Label 
@@ -170,12 +170,16 @@ namespace Beefy.theme.dark
 
         public virtual void MenuClosed()
         {
-			if (mPrevFocusWidget != null)
-			{
-				mPrevFocusWidget.SetFocus();
-			}
+			mPrevFocusWidget?.Value?.SetFocus();
         }
 
+		protected override void RemovedFromWindow()
+		{
+			base.RemovedFromWindow();
+
+			mCurMenuWidget?.mMenu.mOnMenuClosed.Dispose();
+		}
+
         void HandleClose(Menu menu, Menu selectedItem)
         {
             mCurMenuWidget = null;
@@ -186,7 +190,8 @@ namespace Beefy.theme.dark
 
         public virtual MenuWidget ShowDropdown()
         {
-			mPrevFocusWidget = mWidgetWindow.mFocusWidget;
+			if ((mPrevFocusWidget == null) && (mWidgetWindow.mFocusWidget != null))
+				mPrevFocusWidget = new .(mWidgetWindow.mFocusWidget);
 
             float popupXOfs = GS!(5);
             float popupYOfs = GS!(-2);
@@ -302,6 +307,16 @@ namespace Beefy.theme.dark
 			return true;
 		}	
 
+		public void SelectFromLabel()
+		{
+			var label = Label;
+			for (let itemWidget in mCurMenuWidget.mItemWidgets)
+			{
+				if (itemWidget.mMenuItem.mLabel == label)
+					mCurMenuWidget.SetSelection(@itemWidget.Index);
+			}
+		}
+
 		void EditKeyDownHandler(KeyDownEvent evt)
 		{
 			if (!WantsKeyHandling())
@@ -318,13 +333,7 @@ namespace Beefy.theme.dark
 			if ((evt.mKeyCode == .Down) && (mCurMenuWidget == null))
 			{
 				ShowDropdown();
-
-				var label = Label;
-				for (let itemWidget in mCurMenuWidget.mItemWidgets)
-				{
-					if (itemWidget.mMenuItem.mLabel == label)
-						mCurMenuWidget.SetSelection(@itemWidget.Index);
-				}
+				SelectFromLabel();
 			}
 
 			if ((evt.mKeyCode == .Escape) && (mCurMenuWidget != null) && (mEditWidget != null))

+ 41 - 5
BeefLibs/Beefy2D/src/theme/dark/DarkEditWidget.bf

@@ -21,6 +21,7 @@ namespace Beefy.theme.dark
 			}
 
 			public Kind mKind;
+			public int32 mLine = -1;
 
 			public ~this()
 			{
@@ -61,7 +62,8 @@ namespace Beefy.theme.dark
 		public uint32 mViewWhiteSpaceColor;
 		public bool mScrollToStartOnLostFocus;
 		public bool mHiliteCurrentLine;
-		public Dictionary<int, Embed> mEmbeds = new .() ~ DeleteDictionaryAndValues!(_);
+		public Dictionary<int32, Embed> mEmbeds = new .() ~ DeleteDictionaryAndValues!(_);
+		public Range? mLineRange;
 
 		protected static uint32[] sDefaultColors = new uint32[] ( Color.White ) ~ delete _;
 
@@ -498,7 +500,7 @@ namespace Beefy.theme.dark
 				((embed.mKind == .HideLine) && (!hideLine)))
 				selStartX += GS!(4);
 
-			Rect rect = .(selStartX, mLineCoords[lineIdx] - GS!(2), embed.GetWidth(hideLine), mFont.GetLineSpacing() + GS!(4));
+			Rect rect = .(selStartX, mLineCoords[lineIdx] - GS!(1), embed.GetWidth(hideLine), mFont.GetLineSpacing() + GS!(3));
 			if (rect.mY < 0)
 				rect.mY = 0;
 			return rect;
@@ -508,7 +510,6 @@ namespace Beefy.theme.dark
         {            
             base.Draw(g);
 
-			
 #unwarn
             int lineCount = GetLineCount();
             float lineSpacing = mFont.GetLineSpacing();
@@ -588,6 +589,12 @@ namespace Beefy.theme.dark
 			    drewCursor = true;
 			}
 
+			if (mLineRange != null)
+			{
+				firstLine = Math.Max(firstLine, mLineRange.Value.Start);
+				lastLine = Math.Min(lastLine, mLineRange.Value.End - 1);
+			}
+
 			String sectionText = scope String(256);
             for (int lineIdx = firstLine; lineIdx <= lastLine; lineIdx++)
             {
@@ -604,7 +611,7 @@ namespace Beefy.theme.dark
 					continue;
 
 				DarkEditWidgetContent.Embed embed = null;
-				if (mEmbeds.GetValue(lineIdx) case .Ok(out embed))
+				if (mEmbeds.GetValue((.)lineIdx) case .Ok(out embed))
 				{
 					if ((embed.mKind == .HideLine) &&
 						((!IsInCollapseGroup(lineIdx, CursorLine)) || (!mEditWidget.mHasFocus)))
@@ -813,6 +820,20 @@ namespace Beefy.theme.dark
 			return line;
 		}
 
+		public override void PhysCursorMoved(CursorMoveKind moveKind)
+		{
+			base.PhysCursorMoved(moveKind);
+
+			if (mLineRange != null)
+			{
+				var lineAndColumn = CursorLineAndColumn;
+				if (lineAndColumn.mLine < mLineRange.Value.Start)
+					CursorLineAndColumn = .(mLineRange.Value.Start, lineAndColumn.mColumn);
+				else if (lineAndColumn.mLine >= mLineRange.Value.End)
+					CursorLineAndColumn = .(mLineRange.Value.End - 1, lineAndColumn.mColumn);
+			}
+		}
+
         public override bool GetLineCharAtCoord(float x, float y, out int line, out int lineChar, out float overflowX)
         {
 			line = GetLineAt(y);
@@ -1145,7 +1166,7 @@ namespace Beefy.theme.dark
 			
 			bool isOverEmbed = false;
 
-			if (mEmbeds.GetValue(line) case .Ok(let embed))
+			if (mEmbeds.GetValue((.)line) case .Ok(let embed))
 			{
 				Rect embedRect = GetEmbedRect(line, embed);
 				if (embedRect.Contains(x, y))
@@ -1223,6 +1244,21 @@ namespace Beefy.theme.dark
                 mVertScrollbar.mScrollIncrement = scrollIncrement;
         }
 
+		public override void UpdateScrollbarData()
+		{
+			base.UpdateScrollbarData();
+
+			var ewc = mEditWidgetContent as DarkEditWidgetContent;
+			if (ewc.mLineRange != null)
+			{
+				ewc.GetTextData();
+				mVertScrollbar.mContentStart = ewc.mLineCoords[Math.Min(ewc.mLineRange.Value.Start, ewc.mLineCoords.Count - 1)];
+				mVertScrollbar.mContentSize = ewc.mLineCoords[Math.Min(ewc.mLineRange.Value.End, ewc.mLineCoords.Count - 1)] - mVertScrollbar.mContentStart;
+				ScrollPositionChanged();
+				mVertScrollbar.UpdateData();
+			}
+		}
+
         public override void Draw(Graphics g)
         {
             base.Draw(g);

+ 2 - 2
BeefLibs/Beefy2D/src/theme/dark/DarkScrollbar.bf

@@ -125,14 +125,14 @@ namespace Beefy.theme.dark
                 float trackSize = sizeLeft - mThumb.mWidth;
                 float trackPct = (x - btnMargin) / trackSize;
                 double contentPos = (mContentSize - mPageSize) * trackPct;
-                return contentPos;
+                return contentPos + mContentStart;
             }
             else
             {
                 float trackSize = sizeLeft - mThumb.mHeight;
                 float trackPct = (y - btnMargin) / trackSize;
                 double contentPos = (mContentSize - mPageSize) * trackPct;
-                return contentPos;
+                return contentPos + mContentStart;
             }
         }
 

+ 10 - 8
BeefLibs/Beefy2D/src/widgets/EditWidget.bf

@@ -2868,11 +2868,11 @@ namespace Beefy.widgets
                 ExtractString(lineStart, lineEnd - lineStart, outStr); // Full line
         }
 
-        public int GetTextIdx(int line, int charIdx)
+        public int GetTextIdx(int line, int lineChar)
         {
             GetTextData();
             int useLine = Math.Min(line, mData.mLineStarts.Count - 1);
-            return mData.mLineStarts[useLine] + charIdx;
+            return mData.mLineStarts[useLine] + lineChar;
         }
 
         public int GetCharIdIdx(int32 findCharId)
@@ -3139,13 +3139,15 @@ namespace Beefy.widgets
 
             float lineHeight = GetLineHeight(line);
 
+			double yOfs = (mEditWidget.mVertScrollbar?.mContentStart).GetValueOrDefault();
+
             if (mIsMultiline)
             {
-                if (aY < mEditWidget.mVertPos.mDest + mTextInsets.mTop)
+                if (aY < mEditWidget.mVertPos.mDest + mTextInsets.mTop + yOfs)
                 {
                     if (scrollView)
                     {
-                        float scrollPos = aY - mTextInsets.mTop;
+                        double scrollPos = aY - mTextInsets.mTop - yOfs;
                         if (centerView)
                         {                            
                             scrollPos -= mEditWidget.mScrollContentContainer.mHeight * 0.50f;
@@ -3158,7 +3160,7 @@ namespace Beefy.widgets
                         int aLine;
                         int aCharIdx;
                         float overflowX;
-                        GetLineCharAtCoord(aX, (float)mEditWidget.mVertPos.mDest + mTextInsets.mTop, out aLine, out aCharIdx, out overflowX);
+                        GetLineCharAtCoord(aX, (float)(mEditWidget.mVertPos.mDest + mTextInsets.mTop + yOfs), out aLine, out aCharIdx, out overflowX);
 
                         float newX;
                         float newY;
@@ -3169,11 +3171,11 @@ namespace Beefy.widgets
                         MoveCursorTo(aLine, aCharIdx);
                     }
                 }
-                else if (aY + lineHeight + mShowLineBottomPadding > mEditWidget.mVertPos.mDest + mEditWidget.mScrollContentContainer.mHeight)
+                else if (aY + lineHeight + mShowLineBottomPadding > mEditWidget.mVertPos.mDest + mEditWidget.mScrollContentContainer.mHeight + yOfs)
                 {
                     if (scrollView)
                     {
-                        float scrollPos = aY + lineHeight + mShowLineBottomPadding - mEditWidget.mScrollContentContainer.mHeight;
+                        double scrollPos = aY + lineHeight + mShowLineBottomPadding - mEditWidget.mScrollContentContainer.mHeight - yOfs;
                         if (centerView)
                         {
                             // Show slightly more content on bottom
@@ -3183,7 +3185,7 @@ namespace Beefy.widgets
                         mEditWidget.VertScrollTo(scrollPos);
                     }
                     else
-                        MoveCursorToCoord(aX, (float)mEditWidget.mVertPos.mDest + mEditWidget.mScrollContentContainer.mHeight - lineHeight);
+                        MoveCursorToCoord(aX, (float)(mEditWidget.mVertPos.mDest + mEditWidget.mScrollContentContainer.mHeight - lineHeight + yOfs));
                 }
             }
 

+ 10 - 2
BeefLibs/Beefy2D/src/widgets/ScrollableWidget.bf

@@ -121,7 +121,11 @@ namespace Beefy.widgets
 
         public bool VertScrollTo(double vertPos, bool immediate = false)
         {
-            double aVertPos = Math.Max(0, Math.Min(vertPos, mScrollContent.mHeight - mScrollContentContainer.mHeight));
+			float contentHeight = mScrollContent.mHeight;
+			if (mVertScrollbar != null)
+				contentHeight = (float)mVertScrollbar.mContentSize;
+
+            double aVertPos = Math.Max(0, Math.Min(vertPos, contentHeight - mScrollContentContainer.mHeight));
             if (aVertPos == mVertPos.mDest)
                 return false;
 
@@ -200,6 +204,7 @@ namespace Beefy.widgets
                 mHorzScrollbar.UpdateData();
 				MarkDirty();
             }
+
             if ((mVertScrollbar != null) && (mVertScrollbar.mContentPos != mVertPos.v))
             {
                 mVertScrollbar.mContentPos = mVertPos.v;
@@ -208,7 +213,9 @@ namespace Beefy.widgets
             }
             if (mScrollContent != null)
             {
-                mScrollContent.Resize((int32)(-mHorzPos.v), (int32)(-mVertPos.v),
+                mScrollContent.Resize(
+					(int32)(-mHorzPos.v - (mHorzScrollbar?.mContentStart).GetValueOrDefault()),
+					(int32)(-mVertPos.v - (mVertScrollbar?.mContentStart).GetValueOrDefault()),
                     mScrollContent.mWidth, mScrollContent.mHeight);
             }
 
@@ -253,6 +260,7 @@ namespace Beefy.widgets
         public override void MouseWheel(float x, float y, float deltaX, float deltaY)
         {
             base.MouseWheel(x, y, deltaX, deltaY);
+
 			if (deltaY != 0)
 			{
 	            if (mVertScrollbar != null)

+ 14 - 3
BeefLibs/Beefy2D/src/widgets/Scrollbar.bf

@@ -100,6 +100,7 @@ namespace Beefy.widgets
             Vert
         }
 
+		public double mContentStart;
         public double mContentSize;
         public double mPageSize;
         public double mContentPos;        
@@ -120,6 +121,7 @@ namespace Beefy.widgets
         public float mScrollIncrement;
         public bool mAlignItems;
 		public bool mDoAutoClamp = true;
+		public bool mAllowMouseWheel = true;
 
         public Event<ScrollEventHandler> mOnScrollEvent ~ _.Dispose();
 
@@ -147,6 +149,9 @@ namespace Beefy.widgets
 
         public virtual void ScrollTo(double pos)
         {
+			var pos;
+			pos -= mContentStart;
+
 			MarkDirty();
             double oldPos = mContentPos;
 
@@ -161,8 +166,8 @@ namespace Beefy.widgets
             if ((mOnScrollEvent.HasListeners) && (oldPos != mContentPos))
             {
                 ScrollEvent scrollEvent = scope ScrollEvent();
-                scrollEvent.mOldPos = oldPos;
-                scrollEvent.mNewPos = mContentPos;
+                scrollEvent.mOldPos = oldPos + mContentStart;
+                scrollEvent.mNewPos = mContentPos + mContentStart;
                 mOnScrollEvent(scrollEvent);
             }
         }
@@ -176,7 +181,7 @@ namespace Beefy.widgets
 
         public virtual void Scroll(double amt)
         {
-            ScrollTo(mContentPos + amt);            
+            ScrollTo(mContentPos + amt + mContentStart);
         }
 
         public virtual double GetContentPosAt(float x, float y)
@@ -226,6 +231,12 @@ namespace Beefy.widgets
 
         public override void MouseWheel(float x, float y, float deltaX, float deltaY)
         {
+			if (!mAllowMouseWheel)
+			{
+				base.MouseWheel(x, y, deltaX, deltaY);
+				return;
+			}
+
 			float delta = (mOrientation == .Horz) ? deltaX : deltaY;
             Scroll(GetScrollIncrement() * -delta);
         }

+ 23 - 0
BeefLibs/Beefy2D/src/widgets/Widget.bf

@@ -834,4 +834,27 @@ namespace Beefy.widgets
 			return true;
 		}
     }
+
+	class SafeWidgetRef
+	{
+		Widget mWidget;
+
+		public this(Widget widget)
+		{
+			mWidget = widget;
+			mWidget.mOnDeleted.Add(new => OnDelete);
+		}
+
+		public ~this()
+		{
+			mWidget?.mOnDeleted.Remove(scope => OnDelete, true);
+		}
+
+		public Widget Value => mWidget;
+
+		void OnDelete(Widget widget)
+		{
+			mWidget = null;
+		}
+	}
 }

+ 4 - 0
BeefySysLib/BeefySysLib.vcxproj

@@ -1624,6 +1624,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
       <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release Static|x64'">TurnOffAllWarnings</WarningLevel>
       <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">TurnOffAllWarnings</WarningLevel>
     </ClCompile>
+    <ClCompile Include="third_party\miniz\miniz.c" />
     <ClCompile Include="third_party\png\png.c">
       <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level1</WarningLevel>
       <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug Static|Win32'">Level1</WarningLevel>
@@ -1950,6 +1951,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
     <ClCompile Include="util\UTF8.cpp" />
     <ClCompile Include="util\Vector.cpp" />
     <ClCompile Include="util\WorkThread.cpp" />
+    <ClCompile Include="util\ZipFile.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="BFApp.h" />
@@ -2133,6 +2135,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
     <ClInclude Include="third_party\jpeg\transupp.h" />
     <ClInclude Include="third_party\libffi\i686-pc-cygwin\include\ffi.h" />
     <ClInclude Include="third_party\libffi\i686-pc-cygwin\include\ffitarget.h" />
+    <ClInclude Include="third_party\miniz\miniz.h" />
     <ClInclude Include="third_party\png\png.h" />
     <ClInclude Include="third_party\png\pngasmrd.h" />
     <ClInclude Include="third_party\png\pngconf.h" />
@@ -2190,6 +2193,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
     <ClInclude Include="util\UTF8.h" />
     <ClInclude Include="util\Vector.h" />
     <ClInclude Include="util\WorkThread.h" />
+    <ClInclude Include="util\ZipFile.h" />
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win64.asm">

+ 15 - 0
BeefySysLib/BeefySysLib.vcxproj.filters

@@ -75,6 +75,9 @@
     <Filter Include="src\third_party\stb">
       <UniqueIdentifier>{b85b0989-3047-46e9-93d7-5bc352fb0df7}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\third_party\miniz">
+      <UniqueIdentifier>{a159b9ee-1a71-44f5-a412-1e01e20b70c7}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="platform\win\DXRenderDevice.cpp">
@@ -722,6 +725,12 @@
     <ClCompile Include="util\Compress.cpp">
       <Filter>src\util</Filter>
     </ClCompile>
+    <ClCompile Include="third_party\miniz\miniz.c">
+      <Filter>src\third_party\miniz</Filter>
+    </ClCompile>
+    <ClCompile Include="util\ZipFile.cpp">
+      <Filter>src\util</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Common.h">
@@ -1108,6 +1117,12 @@
     <ClInclude Include="util\BitSet.h">
       <Filter>src\util</Filter>
     </ClInclude>
+    <ClInclude Include="third_party\miniz\miniz.h">
+      <Filter>src\third_party\miniz</Filter>
+    </ClInclude>
+    <ClInclude Include="util\ZipFile.h">
+      <Filter>src\util</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">

+ 4 - 0
BeefySysLib/BeefySysLib_static.vcxproj

@@ -677,6 +677,7 @@
       <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Level1</WarningLevel>
       <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Level1</WarningLevel>
     </ClCompile>
+    <ClCompile Include="third_party\miniz\miniz.c" />
     <ClCompile Include="third_party\png\png.c">
       <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Level1</WarningLevel>
       <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Level1</WarningLevel>
@@ -883,6 +884,7 @@
     <ClCompile Include="util\UTF8.cpp" />
     <ClCompile Include="util\Vector.cpp" />
     <ClCompile Include="util\WorkThread.cpp" />
+    <ClCompile Include="util\ZipFile.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="BFApp.h" />
@@ -1007,6 +1009,7 @@
     <ClInclude Include="third_party\jpeg\transupp.h" />
     <ClInclude Include="third_party\libffi\i686-pc-cygwin\include\ffi.h" />
     <ClInclude Include="third_party\libffi\i686-pc-cygwin\include\ffitarget.h" />
+    <ClInclude Include="third_party\miniz\miniz.h" />
     <ClInclude Include="third_party\png\png.h" />
     <ClInclude Include="third_party\png\pngasmrd.h" />
     <ClInclude Include="third_party\png\pngconf.h" />
@@ -1049,6 +1052,7 @@
     <ClInclude Include="util\UTF8.h" />
     <ClInclude Include="util\Vector.h" />
     <ClInclude Include="util\WorkThread.h" />
+    <ClInclude Include="util\ZipFile.h" />
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win64.asm">

+ 15 - 0
BeefySysLib/BeefySysLib_static.vcxproj.filters

@@ -66,6 +66,9 @@
     <Filter Include="src\third_party\utf8proc">
       <UniqueIdentifier>{1309f90f-4745-4623-ab21-5d7b1450103c}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\third_party\miniz">
+      <UniqueIdentifier>{d32cb9b0-e79b-49fe-82e2-33302be0baf6}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="platform\win\DXRenderDevice.cpp">
@@ -575,6 +578,12 @@
     <ClCompile Include="util\Compress.cpp">
       <Filter>src\util</Filter>
     </ClCompile>
+    <ClCompile Include="util\ZipFile.cpp">
+      <Filter>src\util</Filter>
+    </ClCompile>
+    <ClCompile Include="third_party\miniz\miniz.c">
+      <Filter>src\third_party\miniz</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Common.h">
@@ -883,6 +892,12 @@
     <ClInclude Include="util\Compress.h">
       <Filter>src\util</Filter>
     </ClInclude>
+    <ClInclude Include="util\ZipFile.h">
+      <Filter>src\util</Filter>
+    </ClInclude>
+    <ClInclude Include="third_party\miniz\miniz.h">
+      <Filter>src\third_party\miniz</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">

+ 4 - 2
BeefySysLib/Common.cpp

@@ -1152,6 +1152,9 @@ String Beefy::FixPath(const StringImpl& pathIn)
 
 String Beefy::FixPathAndCase(const StringImpl& pathIn)
 {
+	if ((!pathIn.IsEmpty()) && (pathIn[0] == '$'))
+		return pathIn;
+
 	String path = FixPath(pathIn);
 #ifdef _WIN32
 	for (int i = 0; i < (int)path.length(); ++i)
@@ -1180,8 +1183,7 @@ String Beefy::RemoveTrailingSlash(const StringImpl& str)
 
 bool Beefy::FileNameEquals(const StringImpl& filePathA, const StringImpl& filePathB)
 {
-#ifdef _WIN32
-	//return _stricmp(filePathA.c_str(), filePathB.c_str()) == 0;
+#ifdef _WIN32	
 	if (filePathA.length() != filePathB.length())
 		return false;
 	

+ 110 - 0
BeefySysLib/util/ZipFile.cpp

@@ -0,0 +1,110 @@
+#include "ZipFile.h"
+
+extern "C"
+{
+#include "miniz/miniz.h"
+}
+
+USING_NS_BF;
+
+class ZipFile::Data
+{
+public:
+	bool mIsWriter;
+	mz_zip_archive mZip;
+};
+
+ZipFile::ZipFile()
+{
+	mData = NULL;
+}
+
+ZipFile::~ZipFile()
+{
+	if (mData != NULL)
+		Close();
+}
+
+bool ZipFile::Open(const StringImpl& filePath)
+{
+	if (mData != NULL)
+		Close();
+
+	mData = new ZipFile::Data();
+	memset(mData, 0, sizeof(ZipFile::Data));	
+	if (!mz_zip_reader_init_file(&mData->mZip, filePath.c_str(), 0))
+		return false;
+
+	return true;
+}
+
+bool ZipFile::Create(const StringImpl& filePath)
+{
+	if (mData != NULL)
+		Close();
+
+	mData = new ZipFile::Data();	
+	memset(mData, 0, sizeof(ZipFile::Data));	
+	if (!mz_zip_writer_init_file(&mData->mZip, filePath.c_str(), 0))	
+	{
+		delete mData;
+		mData = NULL;
+		return false;
+	}
+
+	mData->mIsWriter = true;
+	return true;
+}
+
+bool ZipFile::Close()
+{
+	if (mData == NULL)
+		return false;
+	
+	if (mData->mIsWriter)
+	{
+		if (!mz_zip_writer_finalize_archive(&mData->mZip))
+			return false;
+		if (!mz_zip_writer_end(&mData->mZip))
+			return false;
+	}
+	else
+	{
+		if (!mz_zip_reader_end(&mData->mZip))
+			return false;
+	}
+
+	return true;
+}
+
+bool ZipFile::IsOpen()
+{
+	return mData != NULL;
+}
+
+bool ZipFile::Add(const StringImpl& fileName, Span<uint8> data)
+{
+	if (mData == NULL)
+		return false;
+
+	if (!mz_zip_writer_add_mem(&mData->mZip, fileName.c_str(), data.mVals, data.mSize, MZ_NO_COMPRESSION))
+		return false;
+
+	return true;
+}
+
+
+bool ZipFile::Get(const StringImpl& fileName, Array<uint8>& data)
+{
+	if (mData == NULL)
+		return false;
+
+	int idx = mz_zip_reader_locate_file(&mData->mZip, fileName.c_str(), NULL, 0);
+	if (idx < 0)
+		return false;
+
+	size_t size = 0;
+	void* ptr = mz_zip_reader_extract_to_heap(&mData->mZip, idx, &size, 0);
+	data.Insert(data.mSize, (uint8*)ptr, (intptr)size);
+	return true;
+}

+ 30 - 0
BeefySysLib/util/ZipFile.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include "../Common.h"
+#include "../Span.h"
+
+NS_BF_BEGIN
+
+
+class ZipFile
+{
+public:
+	class Data;
+
+public:
+	Data* mData;
+
+public:
+	ZipFile();
+	~ZipFile();
+
+	bool Open(const StringImpl& filePath);
+	bool Create(const StringImpl& filePath);
+	bool Close();
+	bool IsOpen();
+	bool Add(const StringImpl& fileName, Span<uint8> data);
+	bool Get(const StringImpl& fileName, Array<uint8>& data);
+};
+
+
+NS_BF_END

+ 11 - 0
IDE/src/BuildContext.bf

@@ -1205,10 +1205,21 @@ namespace IDE
 						linkLine.Append(" /ignore:4099");
 					}
 
+					int targetDotPos = targetPath.LastIndexOf('.');
+					if (targetDotPos != -1)
+					{
+						var writeEmitCmd = new IDEApp.WriteEmitCmd();
+						writeEmitCmd.mPath = new .(targetPath, 0, targetDotPos);
+						writeEmitCmd.mPath.Append("__emit.zip");
+						writeEmitCmd.mProjectName = new .(project.mProjectName);
+						gApp.mExecutionQueue.Add(writeEmitCmd);
+					}
+
 			        var runCmd = gApp.QueueRun(linkerPath, linkLine, gApp.mInstallDir, .UTF16WithBom);
 					runCmd.mReference = new .(project.mProjectName);
 					runCmd.mEnvVars = new .() { (new String("VSLANG"), new String("1033")) };
 			        runCmd.mOnlyIfNotFailed = true;
+
 			        var tagetCompletedCmd = new IDEApp.TargetCompletedCmd(project);
 			        tagetCompletedCmd.mOnlyIfNotFailed = true;
 			        gApp.mExecutionQueue.Add(tagetCompletedCmd);

+ 43 - 8
IDE/src/Compiler/BfCompiler.bf

@@ -58,10 +58,10 @@ namespace IDE.Compiler
 		static extern bool BfCompiler_VerifyTypeName(void* bfCompiler, char8* typeName, int32 cursorPos);
 
         [CallingConvention(.Stdcall), CLink]
-        static extern bool BfCompiler_ClassifySource(void* bfCompiler, void* bfPassInstance, void* bfParser, void* bfResolvePassData, void* char8Data);
+        static extern bool BfCompiler_ClassifySource(void* bfCompiler, void* bfPassInstance, void* bfResolvePassData);
 
 		[CallingConvention(.Stdcall), CLink]
-		static extern char8* BfCompiler_GetCollapseRegions(void* bfCompiler, void* bfParser);
+		static extern char8* BfCompiler_GetCollapseRegions(void* bfCompiler, void* bfParser, void* bfResolvePassData, char8* explicitEmitTypeNames);
 
         [CallingConvention(.Stdcall), CLink]
         static extern char8* BfCompiler_GetAutocompleteInfo(void* bfCompiler);
@@ -135,6 +135,12 @@ namespace IDE.Compiler
 		[CallingConvention(.Stdcall), CLink]
 		static extern char8* BfCompiler_GetTypeInfo(void* bfCompiler, char8* typeName);
 
+		[CallingConvention(.Stdcall), CLink]
+		static extern char8* BfCompiler_GetGenericTypeInstances(void* bfCompiler, char8* typeName);
+
+		[CallingConvention(.Stdcall), CLink]
+		static extern int32 BfCompiler_GetTypeId(void* bfCompiler, char8* typeName);
+
         [CallingConvention(.Stdcall), CLink]
         static extern void BfCompiler_SetOptions(void* bfCompiler,
             void* hotProject, int32 hotIdx, char8* targetTriple, char8* targetCPU, int32 toolsetType, int32 simdSetting, int32 allocStackCount, int32 maxWorkerThreads,
@@ -149,6 +155,12 @@ namespace IDE.Compiler
 		[CallingConvention(.Stdcall), CLink]
 		static extern int32 BfCompiler_GetEmitSourceVersion(void* bfCompiler, char8* fileName);
 
+		[CallingConvention(.Stdcall), CLink]
+		static extern char8* BfCompiler_GetEmitLocation(void* bfCompiler, char8* typeName, int32 line, out int32 embedLine, out int32 embedLineChar);
+
+		[CallingConvention(.Stdcall), CLink]
+		static extern void BfCompiler_WriteEmitData(void* bfCompiler, char8* filePath, void* bfProject);
+		
 		public enum HotTypeFlags
 		{
 			None		= 0,
@@ -260,18 +272,17 @@ namespace IDE.Compiler
 			BfCompiler_ClearResults(mNativeBfCompiler);
 		}
 
-        public bool ClassifySource(BfPassInstance bfPassInstance, BfParser parser, BfResolvePassData resolvePassData, EditWidgetContent.CharData[] char8Data)
+        public bool ClassifySource(BfPassInstance bfPassInstance, BfResolvePassData resolvePassData)
         {
             void* nativeResolvePassData = null;
             if (resolvePassData != null)
                 nativeResolvePassData = resolvePassData.mNativeResolvePassData;
-            EditWidgetContent.CharData* char8DataPtr = (char8Data != null) ? char8Data.CArray() : null;
-            return BfCompiler_ClassifySource(mNativeBfCompiler, bfPassInstance.mNativeBfPassInstance, (parser != null) ? parser.mNativeBfParser : null, nativeResolvePassData, char8DataPtr);                
+            return BfCompiler_ClassifySource(mNativeBfCompiler, bfPassInstance.mNativeBfPassInstance, nativeResolvePassData);
         }
 
-		public void GetCollapseRegions(BfParser parser, String outData)
+		public void GetCollapseRegions(BfParser parser, BfResolvePassData resolvePassData, String explicitEmitTypeNames, String outData)
 		{
-			outData.Append(BfCompiler_GetCollapseRegions(mNativeBfCompiler, (parser != null) ? parser.mNativeBfParser : null));
+			outData.Append(BfCompiler_GetCollapseRegions(mNativeBfCompiler, (parser != null) ? parser.mNativeBfParser : null, resolvePassData.mNativeResolvePassData, explicitEmitTypeNames));
 		}
 
 		public bool VerifyTypeName(String typeName, int cursorPos)
@@ -344,6 +355,15 @@ namespace IDE.Compiler
 			return BfCompiler_GetEmitSourceVersion(mNativeBfCompiler, fileName.ToScopeCStr!());
 		}
 
+		public void GetEmitLocation(StringView typeName, int line, String outFilePath, out int embedLine, out int embedLineChar)
+		{
+			int32 embedLine32;
+			int32 embedLineChar32;
+			outFilePath.Append(BfCompiler_GetEmitLocation(mNativeBfCompiler, typeName.ToScopeCStr!(), (.)line, out embedLine32, out embedLineChar32));
+			embedLine = embedLine32;
+			embedLineChar = embedLineChar32;
+		}
+
         public void QueueSetPassInstance(BfPassInstance passInstance)
         {
             SetPassInstanceCommand command = new SetPassInstanceCommand();
@@ -588,7 +608,7 @@ namespace IDE.Compiler
 
                     var resolvePassData = BfResolvePassData.Create(ResolveType.Classify);
                     // If we get canceled then try again after waiting a couple updates
-                    if (!ClassifySource(passInstance, null, resolvePassData, null))
+                    if (!ClassifySource(passInstance, resolvePassData))
                         QueueDeferredResolveAll();
 					UpdateRebuildFileWatches();
 
@@ -808,11 +828,21 @@ namespace IDE.Compiler
 			outStr.Append(BfCompiler_GetTypeDefInfo(mNativeBfCompiler, typeDefName));
 		}
 
+		public void GetGenericTypeInstances(String typeName, String outStr)
+		{
+			outStr.Append(BfCompiler_GetGenericTypeInstances(mNativeBfCompiler, typeName));
+		}
+
 		public void GetTypeInfo(String typeDefName, String outStr)
 		{
 			outStr.Append(BfCompiler_GetTypeInfo(mNativeBfCompiler, typeDefName));
 		}
 
+		public int GetTypeId(String typeName)
+		{
+			return BfCompiler_GetTypeId(mNativeBfCompiler, typeName);
+		}
+
 		public void ClearBuildCache()
 		{
 			BfCompiler_ClearBuildCache(mNativeBfCompiler);
@@ -943,5 +973,10 @@ namespace IDE.Compiler
 			dirChangedCommand.mDir.Set(str);
 			QueueCommand(dirChangedCommand);
 		}
+
+		public void WriteEmitData(String filePath, BfProject bfProject)
+		{
+			BfCompiler_WriteEmitData(mNativeBfCompiler, filePath, bfProject.mNativeBfProject);
+		}
     }
 }

+ 67 - 23
IDE/src/Compiler/BfParser.bf

@@ -29,29 +29,50 @@ namespace IDE.Compiler
 
     public enum ResolveType
     {
-        None,
-        Classify,
-        ClassifyFullRefresh,
-        Autocomplete,
-        Autocomplete_HighPri,
-        GoToDefinition,
-        GetSymbolInfo,        
-        RenameSymbol,
-        ShowFileSymbolReferences,
-        GetNavigationData,
-		GetCurrentLocation,
-		GetFixits,
-		GetTypeDefList,
-		GetTypeDefInto,
-		GetResultString
+        case None,
+	        Classify,
+	        ClassifyFullRefresh,
+	        Autocomplete,
+	        Autocomplete_HighPri,
+	        GoToDefinition,
+	        GetSymbolInfo,        
+	        RenameSymbol,
+	        ShowFileSymbolReferences,
+	        GetNavigationData,
+			GetCurrentLocation,
+			GetFixits,
+			GetTypeDefList,
+			GetTypeDefInto,
+			GetResultString;
+
+		public bool IsClassify => (this == .Classify) || (this == .ClassifyFullRefresh);
     }
 
+	public enum SourceEmbedKind
+	{
+		None,
+		Type,
+		Method
+	}
+
     public class ResolveParams
     {
+		public class Embed
+		{
+			public String mTypeName ~ delete _;
+			public int32 mRevision = -1;
+			public int32 mCursorIdx = -1;
+			public EditWidgetContent.CharData[] mCharData ~ delete _;
+		}
+
 		public ResolveType mResolveType;
 		public int32 mOverrideCursorPos = -1;
 		public bool mInDeferredList;
 
+		public EditWidgetContent.CharData[] mCharData ~ delete _;
+		public IdSpan mCharIdSpan ~ _.Dispose();
+		public BfParser mParser;
+
         public int32 mLocalId = -1;
         public String mReplaceStr ~ delete _;
         public String mTypeDef ~ delete _;
@@ -71,9 +92,7 @@ namespace IDE.Compiler
 		public WaitEvent mWaitEvent ~ delete _;
 
 		public BfPassInstance mPassInstance ~ delete _;
-		public EditWidgetContent.CharData[] mCharData ~ delete _;
-		public IdSpan mCharIdSpan ~ _.Dispose();
-		public BfParser mParser;
+		public List<Embed> mEmitEmbeds = new .() ~ DeleteContainerAndItems!(_);
 		public String mDocumentationName ~ delete _;
 		public bool mCancelled;
 		public int32 mTextVersion = -1;
@@ -108,13 +127,16 @@ namespace IDE.Compiler
         static extern void BfParser_SetNextRevision(void* bfParser, void* nextParser);
 
         [CallingConvention(.Stdcall), CLink]
-        static extern bool BfParser_SetCursorIdx(void* bfParser, int32 cursorIdx);
+        static extern void BfParser_SetCursorIdx(void* bfParser, int32 cursorIdx);
 
         [CallingConvention(.Stdcall), CLink]
-        static extern bool BfParser_SetAutocomplete(void* bfParser, int32 cursorIdx);
+        static extern void BfParser_SetAutocomplete(void* bfParser, int32 cursorIdx);
+
+		[CallingConvention(.Stdcall), CLink]
+		static extern void BfParser_SetEmbedKind(void* bfParser, SourceEmbedKind embedKind);
 
         [CallingConvention(.Stdcall), CLink]
-        static extern bool BfParser_SetIsClassifying(void* bfParser);
+        static extern void BfParser_SetIsClassifying(void* bfParser);
 
         [CallingConvention(.Stdcall), CLink]
         static extern bool BfParser_Parse(void* bfParser, void* bfPassInstance, bool compatMode);
@@ -140,6 +162,12 @@ namespace IDE.Compiler
         [CallingConvention(.Stdcall), CLink]
         static extern void BfParser_ClassifySource(void* bfParser, void* elementTypeArray, bool preserveFlags);
 
+		[CallingConvention(.Stdcall), CLink]
+        static extern void BfParser_CreateClassifier(void* bfParser, void* passInstance, void* resolvePassData, void* elementTypeArray);
+
+		[CallingConvention(.Stdcall), CLink]
+		static extern void BfParser_FinishClassifier(void* bfParser, void* resolvePassData);
+
         [CallingConvention(.Stdcall), CLink]
         static extern void BfParser_GenerateAutoCompletionFrom(void* bfParser, int32 srcPosition);
 
@@ -168,11 +196,11 @@ namespace IDE.Compiler
 			mNativeBfParser = null;
 		}
 
-        public void SetSource(String data, String fileName)
+        public void SetSource(StringView data, String fileName)
         {
             Debug.Assert(!mIsUsed);
             mIsUsed = true;
-            BfParser_SetSource(mNativeBfParser, data, (int32)data.Length, fileName);
+            BfParser_SetSource(mNativeBfParser, data.Ptr, (int32)data.Length, fileName);
         }
 
         public void SetCharIdData(ref IdSpan char8IdData)
@@ -192,6 +220,11 @@ namespace IDE.Compiler
             BfParser_SetAutocomplete(mNativeBfParser, (int32)cursorIdx);
         }
 
+		public void SetEmbedKind(SourceEmbedKind embedKind)
+		{
+			BfParser_SetEmbedKind(mNativeBfParser, embedKind);
+		}
+
         public void SetIsClassifying()
         {
             BfParser_SetIsClassifying(mNativeBfParser);
@@ -247,6 +280,17 @@ namespace IDE.Compiler
             BfParser_ClassifySource(mNativeBfParser, char8DataPtr, preserveFlags);
         }
 
+		public void CreateClassifier(BfPassInstance passInstance, BfResolvePassData bfResolvePassData, EditWidgetContent.CharData[] charDataArr)
+		{
+			EditWidgetContent.CharData* charDataPtr = charDataArr.CArray();
+			BfParser_CreateClassifier(mNativeBfParser, passInstance.mNativeBfPassInstance, bfResolvePassData.mNativeResolvePassData, charDataPtr);
+		}
+
+		public void FinishClassifier(BfResolvePassData bfResolvePassData)
+		{
+			BfParser_FinishClassifier(mNativeBfParser, bfResolvePassData.mNativeResolvePassData);
+		}
+
         public void SetNextRevision(BfParser nextRevision)
         {
             BfParser_SetNextRevision(mNativeBfParser, nextRevision.mNativeBfParser);

+ 17 - 0
IDE/src/Compiler/BfResolvePassData.bf

@@ -2,6 +2,7 @@ using System;
 using System.Collections;
 using System.Text;
 using System.Threading.Tasks;
+using Beefy.widgets;
 
 namespace IDE.Compiler
 {
@@ -37,6 +38,12 @@ namespace IDE.Compiler
 		[CallingConvention(.Stdcall), CLink]
 		static extern void BfResolvePassData_SetDocumentationRequest(void* bfResolvePassData, char8* entryName);
 
+		[CallingConvention(.Stdcall), CLink]
+		static extern void BfResolvePassData_AddEmitEmbed(void* bfResolvePassData, char8* typeName, int32 cursorIdx);
+
+		[CallingConvention(.Stdcall), CLink]
+		static extern void* BfResolvePassData_GetEmitEmbedData(void* bfResolvePassData, char8* typeName, out int32 srcLength, out int32 revision);
+
         //
 
         //[CallingConvention(.Stdcall), CLink]
@@ -100,5 +107,15 @@ namespace IDE.Compiler
             resolvePassData.mNativeResolvePassData = BfParser.[Friend]BfParser_CreateResolvePassData(null, (int32)resolveType, doFuzzyAutoComplete);
             return resolvePassData;
         }
+
+		public void AddEmitEmbed(char8* typeName, int32 cursorIdx)
+		{
+			BfResolvePassData_AddEmitEmbed(mNativeResolvePassData, typeName, cursorIdx);
+		}
+
+		public EditWidgetContent.CharData* GetEmitEmbedData(char8* typeName, out int32 srcLength, out int32 revision)
+		{
+			return (.)BfResolvePassData_GetEmitEmbedData(mNativeResolvePassData, typeName, out srcLength, out revision);
+		}
     }
 }

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

@@ -372,6 +372,9 @@ namespace IDE.Debugger
 		[CallingConvention(.Stdcall),CLink]
 		static extern int Debugger_GetDbgAllocHeapSize();
 
+		[CallingConvention(.Stdcall), CLink]
+		static extern char8* Debugger_GetEmitSource(char8* fileName);
+
 		public String mRunningPath ~ delete _;
 		public bool mIsRunning;
 		public bool mIsRunningCompiled;
@@ -382,8 +385,9 @@ namespace IDE.Debugger
 		public int32 mActiveCallStackIdx;
 		public Event<Action> mBreakpointsChangedDelegate ~ _.Dispose();
 		public Breakpoint mRunToCursorBreakpoint;
+		public int32 mDebugIdx;
 
-		bool IsRunning
+		public bool IsRunning
 		{
 			get
 			{
@@ -391,6 +395,14 @@ namespace IDE.Debugger
 			}
 		}
 
+		public bool IsRunningUncompiled
+		{
+			get
+			{
+				return mIsRunning && !mIsRunningCompiled;
+			}
+		}
+
 		public this()
 		{
 			Debugger_Create();
@@ -975,7 +987,14 @@ namespace IDE.Debugger
 			stackSize = stackSizeOut;
 
 			if (outFile != null)
+			{
 				outFile.Append(fileStrPtr);
+				if ((outFile.StartsWith("$Emit")) && (mIsRunningCompiled))
+				{
+					int dollarPos = outFile.IndexOf('$', 1);
+					outFile.Remove(5, dollarPos - 5);
+				}
+			}
 			if (outStackFrameInfo != null)
 				outStackFrameInfo.Append(locationStr);
 		}
@@ -1224,5 +1243,14 @@ namespace IDE.Debugger
 		{
 			return Debugger_GetDbgAllocHeapSize();
 		}
+
+		public bool GetEmitSource(StringView fileName, String outText)
+		{
+			char8* str = Debugger_GetEmitSource(fileName.ToScopeCStr!());
+			if (str == null)
+				return false;
+			outText.Append(str);
+			return true;
+		}
 	}
 }

+ 199 - 59
IDE/src/IDEApp.bf

@@ -380,6 +380,12 @@ namespace IDE
             public bool mOnlyIfNotFailed;
         }
 
+		public class WriteEmitCmd : ExecutionCmd
+		{
+			public String mProjectName ~ delete _;
+			public String mPath ~ delete _;
+		}
+
         public class BuildCompletedCmd : ExecutionCmd
         {
             public Stopwatch mStopwatch ~ delete _;
@@ -524,6 +530,18 @@ namespace IDE
         private int32 mStepCount;
         private int32 mNoDebugMessagesTick;
 
+		public class DeferredShowSource
+		{
+			public String mFilePath ~ delete _;
+			public int32 mShowHotIdx;
+			public int32 mRefHotIdx;
+			public int32 mLine;
+			public int32 mColumn;
+			public LocatorType mHilitePosition;
+			public bool mShowTemp;
+		}
+		public DeferredShowSource mDeferredShowSource ~ delete _;
+
         public bool IsCompiling
         {
             get
@@ -1335,7 +1353,7 @@ namespace IDE
             return false;
         }
 
-        public SourceViewPanel GetActiveSourceViewPanel(bool includeLastActive = false)
+        public SourceViewPanel GetActiveSourceViewPanel(bool includeLastActive = false, bool includeEmbeds = false)
         {
 			if (mRunningTestScript)
 				return mLastActiveSourceViewPanel;
@@ -1343,10 +1361,12 @@ namespace IDE
             var activePanel = GetActiveDocumentPanel();
             var sourceViewPanel = activePanel as SourceViewPanel;
 			if (sourceViewPanel != null)
-				return sourceViewPanel.GetActivePanel();
+				sourceViewPanel = sourceViewPanel.GetActivePanel();
 			if ((mLastActiveSourceViewPanel != null) && (includeLastActive))
-				return mLastActiveSourceViewPanel.GetActivePanel();
-			return null;
+				sourceViewPanel = mLastActiveSourceViewPanel.GetActivePanel();
+			if ((sourceViewPanel != null) && (includeEmbeds))
+				sourceViewPanel = sourceViewPanel.GetFocusedEmbeddedView();
+			return sourceViewPanel;
         }
 
         public TextPanel GetActiveTextPanel()
@@ -1461,21 +1481,20 @@ namespace IDE
 				}
 			}
 
-			BfCompiler compiler = null;
-
-			if (fileName.Contains("$EmitR$"))
-				compiler = mBfResolveCompiler;
-			else if (fileName.Contains("$Emit$"))
-				compiler = mBfBuildCompiler;
-
-			if (compiler != null)
+			if (fileName.StartsWith("$Emit$"))
 			{
-				if (compiler.GetEmitSource(fileName, outBuffer))
-				{
-					if (onPreFilter != null)
-						onPreFilter();
+				BfCompiler compiler = mBfResolveCompiler;
+				if (!compiler.IsPerformingBackgroundOperation())
+					compiler.GetEmitSource(fileName, outBuffer);
+				
+				if (onPreFilter != null)
+					onPreFilter();
+				return .Ok;
+			}
+			else if (fileName.StartsWith("$Emit"))
+			{
+				if (mDebugger.GetEmitSource(fileName, outBuffer))
 					return .Ok;
-				}
 			}
 
 			return Utils.LoadTextFile(fileName, outBuffer, autoRetry, onPreFilter);
@@ -4152,7 +4171,7 @@ namespace IDE
 
         public void GoToDefinition(bool force)
         {
-            var sourceViewPanel = GetActiveSourceViewPanel();
+            var sourceViewPanel = GetActiveSourceViewPanel(false, true);
             if (sourceViewPanel != null)
             {
 				if (!force)
@@ -4188,7 +4207,7 @@ namespace IDE
                 }
                 else
 #endif
-                {                    
+                /*{                    
                     ResolveParams resolveParams = scope ResolveParams();
                     sourceViewPanel.Classify(ResolveType.GoToDefinition, resolveParams);
                     if (resolveParams.mOutFileName != null)
@@ -4204,7 +4223,7 @@ namespace IDE
 				{
 	                Fail("Unable to locate definition");
 				}
-				else
+				else*/
 				{
 					sourceViewPanel.ShowSymbolReferenceHelper(.GoToDefinition);
 				}
@@ -4629,6 +4648,7 @@ namespace IDE
 
 			if (var sourceViewPanel = documentPanel as SourceViewPanel)
 			{
+				sourceViewPanel = sourceViewPanel.GetFocusedEmbeddedView();
 			    sourceViewPanel.ToggleBreakpointAtCursor(setKind, setFlags, bindToThread ? gApp.mDebugger.GetActiveThread() : -1);
 			}
 			else if (var disassemblyPanel = documentPanel as DisassemblyPanel)
@@ -6483,9 +6503,10 @@ namespace IDE
 
         public (SourceViewPanel panel, TabbedView.TabButton tabButton) ShowSourceFile(String filePath, ProjectSource projectSource = null, SourceShowType showType = SourceShowType.ShowExisting, bool setFocus = true)
         {
+			DeleteAndNullify!(mDeferredShowSource);
+
 			//TODO: PUT BACK!
 			//return null;
-
 #unwarn
 			String useFilePath = filePath;
 			var useProjectSource = projectSource;
@@ -6604,6 +6625,8 @@ namespace IDE
             else
                 success = sourceViewPanel.Show(useFilePath, !mInitialized);
 			sourceViewPanel.mEmitRevision = emitRevision;
+			if (emitRevision != -1)
+				sourceViewPanel.mEditWidget.mEditWidgetContent.mIsReadOnly = true;
 
             if (!success)
             {
@@ -7051,9 +7074,76 @@ namespace IDE
 
         public SourceViewPanel ShowSourceFileLocation(String filePath, int showHotIdx, int refHotIdx, int line, int column, LocatorType hilitePosition, bool showTemp = false)
         {
-            var sourceViewPanel = ShowSourceFile(filePath, null, showTemp ? SourceShowType.Temp : SourceShowType.ShowExisting).panel;
+			if (filePath.StartsWith("$Emit$"))
+			{
+				var compiler = mBfResolveCompiler;
+				if (compiler.IsPerformingBackgroundOperation())
+				{
+					DeleteAndNullify!(mDeferredShowSource);
+					mDeferredShowSource = new DeferredShowSource()
+						{
+							mFilePath = new .(filePath),
+							mShowHotIdx = (.)showHotIdx,
+							mRefHotIdx = (.)refHotIdx,
+							mLine = (.)line,
+							mColumn = (.)column,
+							mHilitePosition = hilitePosition,
+							mShowTemp = showTemp
+						};
+					return null;
+				}
+
+				var itr = filePath.Split('$');
+				itr.GetNext();
+				itr.GetNext();
+				var typeName = itr.GetNext().Value;
+
+				//var compiler = (kindStr == "Emit") ? mBfBuildCompiler : mBfResolveCompiler;
+				
+				compiler.mBfSystem.Lock(0);
+				var embedFilePath = compiler.GetEmitLocation(typeName, line, .. scope .(), var embedLine, var embedLineChar);
+				compiler.mBfSystem.Unlock();
+
+				if (!embedFilePath.IsEmpty)
+				{
+					var sourceViewPanel = ShowSourceFile(scope .(embedFilePath), null, showTemp ? SourceShowType.Temp : SourceShowType.ShowExisting).panel;
+					if (sourceViewPanel == null)
+					    return null;
+
+					var sewc = sourceViewPanel.mEditWidget.mEditWidgetContent as SourceEditWidgetContent;
+					var data = sewc.mData as SourceEditWidgetContent.Data;
+
+					QueuedEmitShowData emitShowData = new .();
+					emitShowData.mPrevCollapseParseRevision = data.mCollapseParseRevision;
+					emitShowData.mTypeName = new .(typeName);
+					emitShowData.mLine = (.)line;
+					emitShowData.mColumn = (.)column;
+					DeleteAndNullify!(sourceViewPanel.[Friend]mQueuedEmitShowData);
+					sourceViewPanel.[Friend]mQueuedEmitShowData = emitShowData;
+
+					//sourceViewPanel.ShowHotFileIdx(showHotIdx);
+					sourceViewPanel.ShowFileLocation(refHotIdx, embedLine, embedLineChar, .None);
+					//sourceViewPanel.QueueFullRefresh(false);
+					//sourceViewPanel.mBackgroundDelay = 1; // Don't immediately perform the full classify
+
+					if (typeName.Contains('<'))
+					{
+						if (sourceViewPanel.AddExplicitEmitType(typeName))
+							sourceViewPanel.QueueFullRefresh(false);
+					}
+
+					if (!sourceViewPanel.[Friend]mWantsFullRefresh)
+						sourceViewPanel.UpdateQueuedEmitShowData();
+
+					return sourceViewPanel;
+				}
+			}
+
+            var (sourceViewPanel, tabButton) = ShowSourceFile(filePath, null, showTemp ? SourceShowType.Temp : SourceShowType.ShowExisting);
             if (sourceViewPanel == null)
                 return null;
+			if (((filePath.StartsWith("$")) && (var svTabButton = tabButton as SourceViewTabButton)))
+				svTabButton.mIsTemp = true;
             sourceViewPanel.ShowHotFileIdx(showHotIdx);
             sourceViewPanel.ShowFileLocation(refHotIdx, Math.Max(0, line), Math.Max(0, column), hilitePosition);
             return sourceViewPanel;
@@ -7155,6 +7245,10 @@ namespace IDE
 						checkForOldFileInfo = true;
 				}
 			}
+			else if (filePath.StartsWith("$Emit"))
+			{
+				// Check this later
+			}
 			else
 			{
 				if (!File.Exists(filePath))
@@ -7207,6 +7301,12 @@ namespace IDE
 					ShowCallstack();
 				}
 
+				if (filePath.StartsWith("$"))
+				{
+					ShowSourceFileLocation(filePath, hotIdx, hotIdx, line, column, .Smart);
+					return;
+				}
+
                 var (sourceViewPanel, tabButton) = ShowSourceFile(filePath, null, SourceShowType.ShowExisting, setFocus);
                 if (sourceViewPanel != null)
                 {
@@ -7957,6 +8057,8 @@ namespace IDE
 
         public static bool IsBeefFile(String fileName)
         {
+			if (fileName.StartsWith('$'))
+				return true;
             return fileName.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".bf", StringComparison.OrdinalIgnoreCase);
         }
 
@@ -7971,6 +8073,8 @@ namespace IDE
 
 		public static bool IsSourceCode(String fileName)
 		{
+			if (fileName.StartsWith('$'))
+				return true;
 			return fileName.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".bf", StringComparison.OrdinalIgnoreCase) ||
 				fileName.EndsWith(".h", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".cpp", StringComparison.OrdinalIgnoreCase) ||
 				fileName.EndsWith(".c", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".cc", StringComparison.OrdinalIgnoreCase) ||
@@ -8775,6 +8879,30 @@ namespace IDE
 					// Already handled
 					(void)scriptCmd;
 				}
+				else if (var writeEmitCmd = next as WriteEmitCmd)
+				{
+					String projectName = new String(writeEmitCmd.mProjectName);
+					String filePath = new String(writeEmitCmd.mPath);
+
+					mBfBuildCompiler.DoBackground(new () =>
+						{
+							if (var project = mWorkspace.FindProject(projectName))
+							{
+								var bfProject = mBfBuildSystem.GetBfProject(project);
+								if (bfProject != null)
+								{
+									mBfBuildSystem.Lock(0);
+									mBfBuildCompiler.WriteEmitData(filePath, bfProject);
+									mBfBuildSystem.Unlock();
+								}
+							}
+						}
+						~
+						{
+							delete projectName;
+							delete filePath;
+						});
+				}
                 else
                 {
                     Runtime.FatalError("Unknown command");
@@ -10758,49 +10886,49 @@ namespace IDE
 				return;
 			}
 
+			bool hasTempFiles = false;
+			WithTabs(scope [&] (tabButton) =>
+				{
+					if (var svTabButton = tabButton as SourceViewTabButton)
+					{
+						if (svTabButton.mIsTemp)
+							hasTempFiles = true;
+					}
+				});
+
+			if (hasTempFiles)
+			{
+				var dialog = ThemeFactory.mDefault.CreateDialog("Close Temp Files", 
+					"Do you want to close temporary files opened from the debugger?");
+				dialog.mDefaultButton = dialog.AddButton("Yes", new (evt) =>
+					{
+						List<SourceViewTabButton> closeTabs = scope .();
+						WithTabs(scope [&] (tabButton) =>
+							{
+								if (var svTabButton = tabButton as SourceViewTabButton)
+								{
+									if (svTabButton.mIsTemp)
+										closeTabs.Add(svTabButton);
+								}
+							});
+						for (var tab in closeTabs)
+						{
+							CloseDocument(tab.mContent);
+						}	
+					});
+				dialog.AddButton("No", new (evt) =>
+					{
+						
+					});
+				dialog.PopupWindow(GetActiveWindow());
+			}
+
 			if (mCrashDumpPath != null)
 			{
 				DeleteAndNullify!(mCrashDumpPath);
 				mDebugger.Detach();
 				mDebugger.mIsRunning = false;
 				mExecutionPaused = false;
-
-				bool hasTempFiles = false;
-				WithTabs(scope [&] (tabButton) =>
-					{
-						if (var svTabButton = tabButton as SourceViewTabButton)
-						{
-							if (svTabButton.mIsTemp)
-								hasTempFiles = true;
-						}
-					});
-
-				if (hasTempFiles)
-				{
-					var dialog = ThemeFactory.mDefault.CreateDialog("Close Temp Files", 
-						"Do you want to close temporary files referenced in the dump file?");
-					dialog.mDefaultButton = dialog.AddButton("Yes", new (evt) =>
-						{
-							List<SourceViewTabButton> closeTabs = scope .();
-							WithTabs(scope [&] (tabButton) =>
-								{
-									if (var svTabButton = tabButton as SourceViewTabButton)
-									{
-										if (svTabButton.mIsTemp)
-											closeTabs.Add(svTabButton);
-									}
-								});
-							for (var tab in closeTabs)
-							{
-								CloseDocument(tab.mContent);
-							}	
-						});
-					dialog.AddButton("No", new (evt) =>
-						{
-							
-						});
-					dialog.PopupWindow(GetActiveWindow());
-				}
 			}
 
 			if (mDebugger.mIsRunning)
@@ -11349,6 +11477,7 @@ namespace IDE
 			CheckDebugVisualizers();
 
 			mDebugger.mIsRunning = true;
+			mDebugger.mDebugIdx++;
 			WithSourceViewPanels(scope (sourceView) =>
 				{
 					sourceView.RehupAlias();
@@ -11407,6 +11536,7 @@ namespace IDE
 
 			CheckDebugVisualizers();
 			mDebugger.mIsRunning = true;
+			mDebugger.mDebugIdx++;
 			mDebugger.RehupBreakpoints(true);
 			mDebugger.Run();
 			mIsAttachPendingSourceShow = true;
@@ -11866,6 +11996,7 @@ namespace IDE
 				if (mDebugger.OpenMiniDump(mCrashDumpPath))
 				{
 					mDebugger.mIsRunning = true;
+					mDebugger.mDebugIdx++;
 					mExecutionPaused = false; // Make this false so we can detect a Pause immediately
 					mIsAttachPendingSourceShow = true;
 				}
@@ -14015,6 +14146,15 @@ namespace IDE
 			if (IDEApp.sApp.mSpellChecker != null)
 				IDEApp.sApp.mSpellChecker.CheckThreadDone();
 
+			if ((mDeferredShowSource != null) && (mBfResolveCompiler?.IsPerformingBackgroundOperation() == false))
+			{
+				var deferredShowSource = mDeferredShowSource;
+				mDeferredShowSource = null;
+				defer delete deferredShowSource;
+				ShowSourceFileLocation(deferredShowSource.mFilePath, deferredShowSource.mShowHotIdx, deferredShowSource.mRefHotIdx,
+					deferredShowSource.mLine, deferredShowSource.mColumn, deferredShowSource.mHilitePosition, deferredShowSource.mShowTemp);
+			}
+
 			///
 			//TODO: REMOVE
 			//mDebugger.InitiateHotResolve(.ActiveMethods | .Allocations);

+ 42 - 0
IDE/src/IDEUtils.bf

@@ -17,6 +17,48 @@ namespace IDE
 		public const char8 cNativeSlash = Path.DirectorySeparatorChar;
 		public const char8 cOtherSlash = Path.AltDirectorySeparatorChar;        
 
+		public static bool GenericEquals(StringView lhs, StringView rhs)
+		{
+			void SkipGeneric(StringView str, ref int i)
+			{
+				int depth = 0;
+				while (i < str.Length)
+				{
+					char8 c = str[i++];
+					if (c == '<')
+						depth++;
+					if (c == '>')
+					{
+						if (--depth == 0)
+							return;
+					}
+				}
+			}
+
+			int li = 0;
+			int ri = 0;
+
+			while ((li < lhs.Length) && (ri < rhs.Length))
+			{
+				char8 lc = lhs[li];
+				char8 rc = rhs[ri];
+				if (lc != rc)
+					return false;
+
+				if (lc == '<')
+				{
+					SkipGeneric(lhs, ref li);
+					SkipGeneric(rhs, ref ri);
+					continue;
+				}
+
+				li++;
+				ri++;
+			}
+
+			return (li == lhs.Length) && (ri == rhs.Length);
+		}
+
 		public static void AppendWithOptionalQuotes(String targetStr, StringView srcFileName)
 		{
 			bool hasSpace = srcFileName.Contains(' ');

+ 1 - 0
IDE/src/TestManager.bf

@@ -627,6 +627,7 @@ namespace IDE
 					gApp.mDebugger.RehupBreakpoints(true);
 					gApp.mDebugger.Run();
 					gApp.mDebugger.mIsRunning = true;
+					gApp.mDebugger.mDebugIdx++;
 				}
 
 				mTestInstance.mThread.Start(false);

+ 7 - 0
IDE/src/Workspace.bf

@@ -584,6 +584,13 @@ namespace IDE
 		{
 			if (inRelPath.IsEmpty)
 				return;
+
+			if (inRelPath.StartsWith('$'))
+			{
+				outAbsPath.Append(inRelPath);
+				return;
+			}
+
 			Path.GetAbsolutePath(inRelPath, mDir, outAbsPath);
 		}
 

+ 2 - 1
IDE/src/ui/ErrorsPanel.bf

@@ -75,13 +75,14 @@ namespace IDE.ui
 			mErrorLV.AddColumn(40, "Line");
 			mErrorLV.mOnItemMouseDown.Add(new (item, x, y, btnNum, btnCount) =>
 				{
+					ListViewItemMouseDown(item, x, y, btnNum, btnCount);
+
 					if ((btnNum == 0) && (btnCount == 2))
 					{
 						let mainItem = (ErrorsListViewItem)item.GetSubItem(0);
 						mainItem.Goto();
 					}
 
-					ListViewItemMouseDown(item, x, y, btnNum, btnCount);
 					//mErrorLV.GetRoot().SelectItemExclusively()
 				});
 			//let newItem = mErrorLV.GetRoot().CreateChildItem();

+ 5 - 1
IDE/src/ui/OutputWidget.bf

@@ -206,7 +206,11 @@ namespace IDE.ui
 
 			if ((errLine != -1) && (errLineChar != -1) && (filePath != null))
 			{
-				if ((!filePath.Contains('\\')) && (!filePath.Contains('/')) && (!filePath.Contains('.')))
+				if (filePath.StartsWith("$Emit"))
+				{
+					// Is good
+				}
+				else if ((!filePath.Contains('\\')) && (!filePath.Contains('/')) && (!filePath.Contains('.')))
 					return false;
 				IDEApp.sApp.CheckProjectRelativePath(filePath);
 

+ 0 - 4
IDE/src/ui/QuickFind.bf

@@ -277,8 +277,6 @@ namespace IDE.ui
 
         public void FindAll(bool doSelect = true)
         {
-			Debug.WriteLine($"FindAll({doSelect})");
-
             mIsShowingMatches = true;
             mFoundMatches = false;
 
@@ -305,8 +303,6 @@ namespace IDE.ui
             }
             mCurFindIdx = curFindIdx;
             mCurFindCount = 0;
-
-			Debug.WriteLine($"FindAll CurFindIdx{mCurFindIdx} CurFindStart:{mCurFindStart}");
         }
 
         public void ShowCurrentSelection()

+ 43 - 13
IDE/src/ui/RenameSymbolDialog.bf

@@ -135,7 +135,7 @@ namespace IDE.ui
             mVertPos = sourceViewPanel.mEditWidget.mVertPos.mDest;
 
 			mAwaitingGetSymbolInfo = true;
-			CheckGetSymbolInfo(kind == .ShowFileReferences);
+			CheckGetSymbolInfo((kind == .ShowFileReferences) || (kind == .GoToDefinition));
         }
 
 
@@ -153,6 +153,9 @@ namespace IDE.ui
 			if (!mAwaitingGetSymbolInfo)
 				return true;
 
+			if (gApp.mBfResolveCompiler.IsPerformingBackgroundOperationHi())
+				return false;
+
 			if (!force)
 			{
 				if (!gApp.mBfResolveCompiler.HasResolvedAll())
@@ -160,7 +163,7 @@ namespace IDE.ui
 			}
 
 			mAwaitingGetSymbolInfo = false;
-			mSourceViewPanel.Classify(.GetSymbolInfo);
+			mSourceViewPanel.Classify((mKind == .GoToDefinition) ? .GoToDefinition : .GetSymbolInfo);
 			mInitialized = true;
 			mGettingSymbolInfo = true;
 			return true;
@@ -231,9 +234,21 @@ namespace IDE.ui
 					mResolveParams.mNamespace = new String(lineDataItr.GetNext().Get());
 					foundSymbol = true;
 				case "defLoc":
+					StringView filePath = lineDataItr.GetNext().Get();
+					int32 line = int32.Parse(lineDataItr.GetNext().Value);
+					int32 lineChar = int32.Parse(lineDataItr.GetNext().Value);
+
+					if (mKind == .GoToDefinition)
+					{
+					    mSourceViewPanel.RecordHistoryLocation();
+					    var sourceViewPanel = gApp.ShowSourceFileLocation(scope .(filePath), -1, -1, line, lineChar, LocatorType.Smart, true);
+					    sourceViewPanel.RecordHistoryLocation(true);
+						Close();
+						return;
+					}
+
 					if (mKind == .Rename)
 					{
-						StringView filePath = lineDataItr.GetNext().Get();
 						let editData = gApp.GetEditData(scope String(filePath), false, false);
 						if (editData != null)
 						{
@@ -260,6 +275,12 @@ namespace IDE.ui
 				}
             }
 
+			if (mKind == .GoToDefinition)
+			{
+				gApp.Fail("Unable to locate definition");
+				Close();
+			}
+
             if ((!foundSymbol) || (foundStr == null))
             {
                 if ((mKind == .Rename) || (mKind == .FindAllReferences))
@@ -829,13 +850,22 @@ namespace IDE.ui
         {
             base.Update();
 
+			if ((mUpdatingProjectSources == null) && (mUpdateCnt > 30) && (gApp.mUpdateCnt % 4 == 0))
+				MarkDirty();
+
+			if (mAwaitingGetSymbolInfo)
+			{
+				if (!CheckGetSymbolInfo(false))
+					return;
+			}
+
 			if (mKind == .GoToDefinition)
 			{
-				if (gApp.mBfResolveCompiler.HasResolvedAll())
+				/*if (gApp.mBfResolveCompiler.HasResolvedAll())
 				{
 					Close();
 					gApp.GoToDefinition(true);
-				}
+				}*/
 
 				if (mSourceViewPanel.EditWidget.Content.CursorTextPos != mCursorPos)
 				{
@@ -845,12 +875,6 @@ namespace IDE.ui
 				return;
 			}
 
-			if (mAwaitingGetSymbolInfo)
-			{
-				if (!CheckGetSymbolInfo(false))
-					return;
-			}
-
 			if (mStartingWork)
 				return;
 
@@ -899,7 +923,7 @@ namespace IDE.ui
 
 			mClosed = true;
 
-			mSourceViewPanel.CancelResolve(.GetSymbolInfo);
+			mSourceViewPanel.CancelResolve((mKind == .GoToDefinition) ? .GoToDefinition : .GetSymbolInfo);
 			if (mBackgroundKind != .None)
 			{
 				gApp.mBfResolveCompiler.CancelBackground();
@@ -921,6 +945,12 @@ namespace IDE.ui
             if (mKind == Kind.ShowFileReferences)
                 return;
 
+			if ((mKind == .GoToDefinition) && (mUpdateCnt < 40))
+			{
+				// Reduce "flashing" for very fast finds
+				return;
+			}
+
 			int symCount = 0;
 			int readOnlyRefCount = 0;
 			int lockedFileCount = 0;
@@ -993,7 +1023,7 @@ namespace IDE.ui
                 }
             }
 
-            if ((mUpdatingProjectSources == null) && (mUpdateCnt > 30))            
+            if ((mUpdatingProjectSources == null) && (mUpdateCnt > 30))
                 IDEUtils.DrawWait(g, mWidth / 2, mHeight / 2 + 4, mUpdateCnt);
         }
 

+ 651 - 30
IDE/src/ui/SourceEditWidgetContent.bf

@@ -13,6 +13,7 @@ using Beefy.utils;
 using IDE.Debugger;
 using IDE.Compiler;
 using Beefy.geom;
+using Beefy.events;
 
 namespace IDE.ui
 {    
@@ -180,19 +181,393 @@ namespace IDE.ui
 			}
 		}
 
+		public class EmitEmbed : DarkEditWidgetContent.Embed
+		{
+			public class View : Widget
+			{
+				public class GenericTypeEntry
+				{
+					public String mTypeName ~ delete _;
+				}
+
+				public enum WorkState
+				{
+					Idle,
+					Queued,
+					Performing,
+					Done
+				}
+
+				public EmitEmbed mEmitEmbed;
+				public String mTypeName ~ delete _;
+				public SourceViewPanel mSourceViewPanel;
+				public DarkComboBox mGenericTypeCombo;
+				public DarkComboBox mGenericMethodCombo;
+				public String mGenericTypeFilter;
+				public float mWantHeight;
+				public float? mMouseDownY;
+				public float? mDownWantHeight;
+
+				public float MinHeight => (mGenericTypeCombo != null) ? GS!(96+25) : GS!(96);
+				public float MaxAutoHeight => GS!(364);
+				public float HeightAdd => (mGenericTypeCombo != null) ? GS!(28+25) : GS!(28);
+
+				public int32 mCollapseParseRevision;
+				public List<GenericTypeEntry> mGenericTypeData = new .() ~ DeleteContainerAndItems!(_);
+				public Monitor mMonitor = new .() ~ delete _;
+				public WorkState mTypeWorkState;
+				public bool mAwaitingLoad;
+				bool mIgnoreChange = false;
+
+				public this(EmitEmbed emitEmbed)
+				{
+					mTypeName = new .(emitEmbed.mTypeName);
+					mEmitEmbed = emitEmbed;
+					mSourceViewPanel = new SourceViewPanel((emitEmbed.mEmitKind == .Method) ? .Method : .Type);
+					mSourceViewPanel.mEmbedParent = mEmitEmbed.mEditWidgetContent.mSourceViewPanel;
+					var emitPath = scope $"$Emit${emitEmbed.mTypeName}";
+
+					mSourceViewPanel.Show(emitPath, false, null);
+					mSourceViewPanel.mEditWidget.mEditWidgetContent.mIsReadOnly = true;
+					mSourceViewPanel.mEmitRevision = emitEmbed.mRevision;
+					AddWidget(mSourceViewPanel);
+
+					mSourceViewPanel.mEditWidget.mOnGotFocus.Add(new (val1) =>
+						{
+							if (mGenericTypeCombo != null)
+								UpdateGenericTypeCombo();
+						});
+
+					mSourceViewPanel.mEditWidget.mHorzScrollbar.mAllowMouseWheel = false;
+					mSourceViewPanel.mEditWidget.mVertScrollbar.mAllowMouseWheel = false;
+
+					var sewc = mSourceViewPanel.mEditWidget.mEditWidgetContent as SourceEditWidgetContent;
+					sewc.mLineRange = Range(emitEmbed.mStartLine, emitEmbed.mEndLine);
+					sewc.mAllowMaximalScroll = false;
+					mSourceViewPanel.mEditWidget.UpdateScrollbars();
+
+					mClipGfx = true;
+
+					if (mTypeName.Contains('<'))
+					{
+						mGenericTypeCombo = new DarkComboBox();
+						mGenericTypeCombo.mFocusDropdown = false;
+						mGenericTypeCombo.mLabelAlign = .Left;
+						mGenericTypeCombo.MakeEditable();
+						UpdateGenericTypeCombo();
+						mGenericTypeCombo.mPopulateMenuAction.Add(new => PopulateTypeData);
+						AddWidget(mGenericTypeCombo);
+
+						mGenericTypeCombo.mEditWidget.mOnContentChanged.Add(new => GenericTypeEditChanged);
+						mGenericTypeCombo.mEditWidget.mOnKeyDown.Add(new => EditKeyDownHandler);
+						mGenericTypeCombo.mEditWidget.mOnGotFocus.Add(new (widget) => mGenericTypeCombo.mEditWidget.mEditWidgetContent.SelectAll());
+					}
+				}
+
+				private void GenericTypeEditChanged(EditEvent theEvent)
+				{
+					if (mIgnoreChange)
+						return;
+
+				    var editWidget = (EditWidget)theEvent.mSender;
+				    var searchText = scope String();
+				    editWidget.GetText(searchText);
+					searchText.Trim();
+
+				    mGenericTypeFilter = searchText;
+				    mGenericTypeCombo.ShowDropdown();
+				    mGenericTypeFilter = null;
+				}
+
+				void EditKeyDownHandler(KeyDownEvent evt)
+				{
+				    if (evt.mKeyCode == KeyCode.Escape)
+				        mEmitEmbed.mEditWidgetContent.mSourceViewPanel.FocusEdit();
+				}
+
+				void UpdateGenericTypeCombo()
+				{
+					var typeName = mEmitEmbed.mTypeName;
+					for (var explicitTypeName in mEmitEmbed.mEditWidgetContent.mSourceViewPanel.[Friend]mExplicitEmitTypes)
+					{
+						if (IDEUtils.GenericEquals(typeName, explicitTypeName))
+							typeName = explicitTypeName;
+					}
+
+					mIgnoreChange = true;
+					int colonPos = typeName.IndexOf(':');
+					if (colonPos != -1)
+						mGenericTypeCombo.Label = typeName.Substring(colonPos + 1);
+					else
+						mGenericTypeCombo.Label = typeName;
+					mIgnoreChange = false;
+				}
+
+				void PopulateTypeData(Menu menu)
+				{
+					List<StringView> findStrs = null;
+					if (mGenericTypeFilter != null)
+					 	findStrs = scope:: List<StringView>(mGenericTypeFilter.Split(' '));
+
+					using (mMonitor.Enter())
+					{
+						EntryLoop: for (var entry in mGenericTypeData)
+						{
+							StringView useName = entry.mTypeName;
+							int colonPos = useName.IndexOf(':');
+							if (colonPos != -1)
+								useName.RemoveFromStart(colonPos + 1);
+
+							if (findStrs != null)
+							{
+								for (let findStr in findStrs)
+								{
+								    if (useName.IndexOf(findStr, true) == -1)
+								        continue EntryLoop;
+								}
+							}
+
+							var item = menu.AddItem(useName);
+
+							var origName = new String(entry.mTypeName);
+							item.mOnMenuItemSelected.Add(new (menu) =>
+								{
+									mEmitEmbed.mEditWidgetContent.mSourceViewPanel.AddExplicitEmitType(origName);
+									mEmitEmbed.mEditWidgetContent.mSourceViewPanel.QueueFullRefresh(false);
+									UpdateGenericTypeCombo();
+									mGenericTypeCombo.mEditWidget.SetFocus();
+								}
+								~
+								{
+									delete origName;
+								});
+						}
+					}
+					
+					if ((mTypeWorkState == .Idle) && (mCollapseParseRevision != mEmitEmbed.mEditWidgetContent.mCollapseParseRevision))
+					{
+						mCollapseParseRevision = mEmitEmbed.mEditWidgetContent.mCollapseParseRevision;
+						mTypeWorkState = .Queued;
+					}
+
+					/*menu.AddItem("Abc");
+					menu.AddItem("Def");*/
+				}
+
+				public override void Update()
+				{
+					base.Update();
+
+					using (mMonitor.Enter())
+					{
+						if ((mTypeWorkState == .Queued) && (gApp?.mBfResolveCompiler.IsPerformingBackgroundOperation() == false))
+						{
+							mTypeWorkState = .Performing;
+							gApp.mBfResolveCompiler.DoBackground(new => GetGenericTypes);
+						}
+
+						if (mTypeWorkState == .Done)
+						{
+							mGenericTypeCombo.ShowDropdown();
+							mGenericTypeCombo.SelectFromLabel();
+							mTypeWorkState = .Idle;
+						}
+					}
+
+					mAwaitingLoad = false;
+					for (var explicitTypeName in mEmitEmbed.mEditWidgetContent.mSourceViewPanel.[Friend]mExplicitEmitTypes)
+					{
+						if ((IDEUtils.GenericEquals(mTypeName, explicitTypeName)) && (mTypeName != explicitTypeName))
+							mAwaitingLoad = true;
+					}
+
+					if (mSourceViewPanel.mEditWidget.mEditWidgetContent.mData.mTextLength == 0)
+						mAwaitingLoad = true;
+
+					if ((mAwaitingLoad) && (gApp.mUpdateCnt % 4 == 0))
+						MarkDirty();
+				}
+
+				public void GetGenericTypes()
+				{
+					gApp.mBfResolveSystem.Lock(0);
+					var genericTypeNames = gApp.mBfResolveCompiler.GetGenericTypeInstances(mTypeName, .. scope .());
+					gApp.mBfResolveSystem.Unlock();
+
+					using (mMonitor.Enter())
+					{
+						mGenericTypeData.ClearAndDeleteItems();
+						mTypeWorkState = .Done;
+
+						for (var genericTypeName in genericTypeNames.Split('\n', .RemoveEmptyEntries))
+						{
+							GenericTypeEntry entry = new .();
+							entry.mTypeName = new .(genericTypeName);
+							mGenericTypeData.Add(entry);
+							mGenericTypeData.Sort(scope (lhs, rhs) => lhs.mTypeName <=> rhs.mTypeName);
+						}
+					}
+				}
+
+				public override void DrawAll(Graphics g)
+				{
+					base.DrawAll(g);
+
+					if (mAwaitingLoad)
+					{
+						var rect = mSourceViewPanel.mEditWidget.GetRect();
+						mSourceViewPanel.mEditWidget.SelfToOtherTranslate(this, 0, 0, out rect.mX, out rect.mY);
+
+						using (g.PushColor(Color.Mult(gApp.mSettings.mUISettings.mColors.mWindow, 0x60FFFFFF)))
+						{
+							g.FillRect(rect.mX, rect.mY, rect.mWidth, rect.mHeight);
+						}
+						IDEUtils.DrawWait(g, rect.mX + rect.mWidth / 2, rect.mY + rect.mHeight / 2, mUpdateCnt);
+					}
+				}
+
+				public override void Resize(float x, float y, float width, float height)
+				{
+					base.Resize(x, y, width, height);
+
+					float curY = GS!(2);
+					if (mGenericTypeCombo != null)
+					{
+						mGenericTypeCombo.Resize(GS!(38), curY, Math.Max(0, width - GS!(38)), GS!(22));
+						curY += GS!(25);
+					}
+
+					mSourceViewPanel.Resize(0, curY, width, Math.Max(0, height - curY - GS!(7)));
+				}
+
+				public void SizeTo(float x, float y, float width, float height)
+				{
+					Resize(x, y, width, height + GS!(3));
+				}
+
+				public override void RehupScale(float oldScale, float newScale)
+				{
+					base.RehupScale(oldScale, newScale);
+					mWantHeight = mWantHeight * newScale / oldScale;
+				}
+
+				public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
+				{
+					base.MouseDown(x, y, btn, btnCount);
+					if (btn == 0)
+					{
+						mMouseDownY = y;
+						mDownWantHeight = mWantHeight;
+					}
+				}
+
+				public override void MouseUp(float x, float y, int32 btn)
+				{
+					base.MouseUp(x, y, btn);
+					if (btn == 0)
+					{
+						mMouseDownY = null;
+						mDownWantHeight = null;
+					}
+				}
+
+				public override void MouseMove(float x, float y)
+				{
+					base.MouseMove(x, y);
+
+					if (mMouseDownY != null)
+					{
+						mWantHeight = Math.Max(MinHeight, mDownWantHeight.Value + y - mMouseDownY.Value);
+						mEmitEmbed.mEditWidgetContent.RehupLineCoords();
+					}
+
+					if (y > mHeight - GS!(6))
+						gApp.SetCursor(.SizeNS);
+				}
+
+				public override void MouseLeave()
+				{
+					base.MouseLeave();
+					gApp.SetCursor(.Pointer);
+				}
+			}
+
+			public SourceEditWidgetContent mEditWidgetContent;
+			public SourceEditWidgetContent.CollapseData.Kind mEmitKind;
+			public String mTypeName;
+			public bool mIsOpen;
+			public float mOpenPct;
+			public int32 mAnchorId;
+			public int32 mCollapseIndex;
+			public int32 mRevision;
+			public int32 mPartialIdx;
+			public int32 mStartLine;
+			public int32 mEndLine;
+			public View mView;
+
+			public ~this()
+			{
+				if (mView != null)
+				{
+					mView.RemoveSelf();
+					delete mView;
+				}
+			}
+
+			public override float GetWidth(bool hideLine)
+			{
+				return GS!(42);
+			}
+
+			public override void Draw(Graphics g, Rect rect, bool hideLine)
+			{
+				if (rect.mHeight >= DarkTheme.sDarkTheme.mSmallBoldFont.GetLineSpacing())
+					g.SetFont(DarkTheme.sDarkTheme.mSmallBoldFont);
+
+				using (g.PushColor(0x20FFFFFF))
+				{
+					g.FillRect(rect.mX, rect.mY, rect.mWidth, rect.mHeight);
+				}
+
+				if ((mEditWidgetContent.mSelection != null) && (mCollapseIndex < mEditWidgetContent.mOrderedCollapseEntries.Count))
+				{
+					var collapseEntry = mEditWidgetContent.mOrderedCollapseEntries[mCollapseIndex];
+					int32 startIdx = mEditWidgetContent.mData.mLineStarts[collapseEntry.mStartLine];
+					if ((mEditWidgetContent.mSelection.Value.MinPos <= collapseEntry.mEndIdx) && (mEditWidgetContent.mSelection.Value.MaxPos >= startIdx))
+					{
+						using (g.PushColor(mEditWidgetContent.GetSelectionColor(0)))
+							g.FillRect(rect.mX, rect.mY, rect.mWidth, rect.mHeight);
+					}
+				}
+
+				using (g.PushColor(0x48FFFFFF))
+				{
+					g.OutlineRect(rect.mX, rect.mY, rect.mWidth, rect.mHeight);
+				}
+
+				var summaryString = "Emit";
+				g.DrawString(summaryString, rect.mX, rect.mY + (int)((rect.mHeight - g.mFont.GetLineSpacing()) * 0.5f), .Centered, rect.mWidth);
+			}
+		}
+
 		public struct CollapseData
 		{
 			public enum Kind : char8
 			{
-				Zero = 0,
-				Comment = 'C',
-				Method = 'M',
-				Namespace = 'N',
-				Property = 'P',
-				Region = 'R',
-				Type = 'T',
-				UsingNamespaces = 'U',
-				Unknown = '?'
+				case Zero = 0;
+				case Comment = 'C';
+				case Method = 'M';
+				case Namespace = 'N';
+				case Property = 'P';
+				case Region = 'R';
+				case Type = 'T';
+				case UsingNamespaces = 'U';
+				case Unknown = '?';
+				case EmitInType = 't';
+				case EmitInMethod = 'm';
+				case EmitAddType = '+';
+
+				public bool IsEmit => (this == .EmitInType) || (this == .EmitInMethod);
 			}
 
 			public Kind mKind;
@@ -218,6 +593,19 @@ namespace IDE.ui
 			public bool mDeleted;
 		}
 
+		public struct EmitData
+		{
+			public SourceEditWidgetContent.CollapseEntry.Kind mKind;
+			public int32 mTypeNameIdx;
+			public int32 mRevision;
+			public int32 mPartialIdx;
+			public int32 mAnchorIdx;
+			public int32 mStartLine;
+			public int32 mEndLine;
+
+			public int32 mAnchorId;
+		}
+
 		public class Data : DarkEditWidgetContent.Data
 		{
 			public List<PersistentTextPosition> mPersistentTextPositions = new List<PersistentTextPosition>() ~ DeleteContainerAndItems!(_);
@@ -225,6 +613,19 @@ namespace IDE.ui
 			public int32 mCollapseParseRevision;
 			public int32 mCollapseTextVersionId;
 			public List<CollapseData> mCollapseData = new .() ~ delete _;
+			public List<EmitData> mEmitData = new .() ~ delete _;
+			public List<String> mTypeNames = new .() ~ DeleteContainerAndItems!(_);
+
+			public void Clear()
+			{
+				mCollapseData.Clear();
+				mEmitData.Clear();
+				ClearAndDeleteItems(mTypeNames);
+			}
+
+			public ~this()
+			{
+			}
 		}
 
 		struct QueuedTextEntry
@@ -327,6 +728,7 @@ namespace IDE.ui
 		HilitePairedCharState mHilitePairedCharState = .NeedToRecalculate;
 		public Dictionary<int32, CollapseEntry> mCollapseMap = new .() ~ delete _;
 		public List<CollapseEntry*> mOrderedCollapseEntries = new .() ~ delete _;
+		public List<String> mCollapseTypeNames = new .() ~ DeleteContainerAndItems!(_);
 		public int32 mCollapseParseRevision;
 		public int32 mCollapseTextVersionId;
 		public bool mCollapseNeedsUpdate;
@@ -421,6 +823,12 @@ namespace IDE.ui
 		    String curText = scope String();
 		    mEditWidget.GetText(curText);
 
+			if (curText == text)
+			{
+				// No change
+				return true;
+			}
+
 		    char8* diffCmdsPtr = BfDiff_DiffText(curText, text);
 		    String diffCmds = scope String();
 			diffCmds.Append(diffCmdsPtr);
@@ -4538,15 +4946,20 @@ namespace IDE.ui
 		public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
 		{
 			int line = GetLineAt(y);
-			if (mEmbeds.GetValue(line) case .Ok(let embed))
+			if (mEmbeds.GetValue((.)line) case .Ok(let embed))
 			{
 				Rect embedRect = GetEmbedRect(line, embed);
 				if (embedRect.Contains(x, y))
 				{
-					if ((btn == 0) && (btnCount == 2))
+					if ((btn == 0) && (btnCount % 2 == 0))
 					{
 						if (var collapseSummary = embed as SourceEditWidgetContent.CollapseSummary)
 							SetCollapseOpen(collapseSummary.mCollapseIndex, true);
+						else if (var emitEmbed = embed as EmitEmbed)
+						{
+							emitEmbed.mIsOpen = !emitEmbed.mIsOpen;
+							mCollapseNeedsUpdate = true;
+						}
 					}
 					return;
 				}
@@ -5047,10 +5460,23 @@ namespace IDE.ui
 			if (mLineCoordJumpTable == null)
 				mLineCoordJumpTable = new .();
 
+			if (data.mLineStarts == null)
+				return;
+
 			mLineCoords.Clear();
 			mLineCoords.GrowUnitialized(data.mLineStarts.Count);
 			mLineCoordJumpTable.Clear();
 
+			List<(int32 line, EmitEmbed emitEmbed)> orderedEmitEmbeds = scope .();
+			for (var entry in mEmbeds)
+			{
+				if (var emitEmbed = entry.value as EmitEmbed)
+				{
+					orderedEmitEmbeds.Add((entry.key, emitEmbed));
+				}
+			}
+			orderedEmitEmbeds.Sort(scope (lhs, rhs) => lhs.line <=> rhs.line);
+			
 			float fontHeight = mFont.GetLineSpacing();
 			int prevJumpIdx = -1;
 			float jumpCoordSpacing = GetJumpCoordSpacing();
@@ -5067,6 +5493,7 @@ namespace IDE.ui
 			int32 curAnimLineIdx = 0;
 			bool inAnim = false;
 			int checkOpenIdx = 0;
+			int orderedEmebedIdx = 0;
 
 			for (int line < data.mLineStarts.Count)
 			{
@@ -5129,6 +5556,28 @@ namespace IDE.ui
 						lineHeight = 0;
 				}
 
+				if ((orderedEmebedIdx < orderedEmitEmbeds.Count) && (line == orderedEmitEmbeds[orderedEmebedIdx].line))
+				{
+					var emitEmbed = orderedEmitEmbeds[orderedEmebedIdx++].emitEmbed;
+					if (lineHeight == 0)
+					{
+						if (emitEmbed.mView != null)
+							emitEmbed.mView.SetVisible(false);
+					}
+					else if (emitEmbed.mView != null)
+					{
+						if (emitEmbed.mView.mWantHeight == 0)
+						{
+							emitEmbed.mView.mWantHeight = Math.Clamp((emitEmbed.mEndLine - emitEmbed.mStartLine) * gApp.mCodeFont.GetLineSpacing() + emitEmbed.mView.HeightAdd,
+								emitEmbed.mView.MinHeight, emitEmbed.mView.MaxAutoHeight);
+						}
+
+						float height = emitEmbed.mView.mWantHeight * emitEmbed.mOpenPct;
+						emitEmbed.mView.SizeTo(GS!(0), (float)curY + lineHeight, mParent.mWidth, height);
+						lineHeight += height;
+					}
+				}
+
 				mLineCoords[line] = (float)curY;
 
 				int jumpIdx = (.)(curY / jumpCoordSpacing);
@@ -5200,13 +5649,88 @@ namespace IDE.ui
 			{
 				mCollapseParseRevision = data.mCollapseParseRevision;
 				mCollapseTextVersionId = data.mCollapseTextVersionId;
+				mCollapseTypeNames.ClearAndDeleteItems();
+				for (var name in data.mTypeNames)
+					mCollapseTypeNames.Add(new .(name));
+
+				Dictionary<int, EmitEmbed> emitEmbedMap = scope .(64);
+				for (var embed in mEmbeds.Values)
+				{
+					if (var emitEmbed = embed as SourceEditWidgetContent.EmitEmbed)
+					{
+						emitEmbedMap[emitEmbed.mAnchorId] = emitEmbed;
+					}
+				}
+
+				for (var emitData in ref data.mEmitData)
+				{
+					GetLineCharAtIdx(emitData.mAnchorIdx, var line, var lineChar);
+
+					SourceEditWidgetContent.EmitEmbed emitEmbed = null;
+					if (emitEmbedMap.GetAndRemove(emitData.mAnchorId) case .Ok((?, out emitEmbed)))
+					{
+						if (line != emitEmbed.mLine)
+						{
+						   	mEmbeds.Remove(emitEmbed.mLine);
+							emitEmbed.mLine = (.)line;
+							mEmbeds[(.)line] = emitEmbed;
+						}
+					}
+					else if (mEmbeds.TryAdd((.)line, var keyPtr, var valuePtr))
+					{
+						emitEmbed = new .();
+						*valuePtr = emitEmbed;
+					}
+					else 
+					{
+						emitEmbed = *valuePtr as SourceEditWidgetContent.EmitEmbed;
+					}
+
+					if (emitEmbed == null)
+						continue;
+
+					emitEmbed.mLine = (.)line;
+					emitEmbed.mAnchorId = emitData.mAnchorId;
+					emitEmbed.mEmitKind = emitData.mKind;
+					emitEmbed.mTypeName = mCollapseTypeNames[emitData.mTypeNameIdx];
+					emitEmbed.mRevision = emitData.mRevision;
+					emitEmbed.mPartialIdx = emitData.mPartialIdx;
+
+					if (emitEmbed.mView != null)
+					{
+						Range range = .(emitData.mStartLine, emitData.mEndLine);
+						var ew = emitEmbed.mView.mSourceViewPanel.mEditWidget;
+						var ewc = ew.mEditWidgetContent as DarkEditWidgetContent;
+						if (ewc.mLineRange != range)
+						{
+							ewc.mLineRange = range;
+							ew.UpdateScrollbars();
+						}
+					}
+
+					emitEmbed.mStartLine = emitData.mStartLine;
+					emitEmbed.mEndLine = emitData.mEndLine;
+					emitEmbed.mEditWidgetContent = this;
+					emitEmbed.mCollapseIndex = (.)emitData.mAnchorIdx;
+					emitEmbed.mKind = .LineEnd;
+				}
+
+				for (var emitEmbed in emitEmbedMap.Values)
+				{
+					mCollapseNeedsUpdate = true;
+					mEmbeds.Remove(emitEmbed.mLine);
+					delete emitEmbed;
+				}
 
 				for (var collapseData in ref data.mCollapseData)
 				{
 					if (mCollapseMap.TryAdd(collapseData.mAnchorId, ?, var entry))
+					{
 						*entry = .();
+					}
+					int32 prevAnchorLine = entry.mAnchorLine;
 					Internal.MemCpy(entry, &collapseData, sizeof(CollapseData));
-					entry.mPrevAnchorLine = entry.mAnchorLine;
+					entry.mPrevAnchorLine = prevAnchorLine;
 					entry.mParseRevision = mCollapseParseRevision;
 					entry.mDeleted = false;
 				}
@@ -5216,7 +5740,10 @@ namespace IDE.ui
 					if (entry.mParseRevision != data.mCollapseParseRevision)
 					{
 						if (mEmbeds.GetAndRemove(entry.mAnchorLine) case .Ok(let val))
-							delete val.value;
+						{
+							if (val.value is CollapseSummary)
+								delete val.value;
+						}
 						@entry.Remove();
 					}
 				}
@@ -5236,23 +5763,31 @@ namespace IDE.ui
 					if (entry.mDeleted)
 					{
 						if (mEmbeds.GetAndRemove(entry.mAnchorIdx) case .Ok(let val))
-							delete val.value;
+						{
+							if (val.value is CollapseSummary)
+								delete val.value;
+						}
 						continue;
 					}
 
 					if ((entry.mPrevAnchorLine != -1) && (entry.mPrevAnchorLine != entry.mAnchorLine))
 					{
-						if (mEmbeds.GetAndRemove(entry.mPrevAnchorLine) case .Ok(let val))
+						if (!mEmbeds.TryGetValue(entry.mPrevAnchorLine, let val))
+							continue;
+
+						if (!(val is CollapseSummary))
+							continue;
+						mEmbeds.Remove(entry.mPrevAnchorLine);
+					
+						if (mEmbeds.TryAdd(entry.mAnchorLine, var keyPtr, var valuePtr))
 						{
-							if (!mEmbeds.TryAdd(entry.mAnchorLine, var keyPtr, var valuePtr))
-							{
-								if (var collapseSummary = val.value as SourceEditWidgetContent.CollapseSummary)
-									collapseSummary.mCollapseIndex = (.)@entry.Index;
-								*valuePtr = val.value;
-							}
-							else
-								delete val.value;
-						}	
+							if (var collapseSummary = val as SourceEditWidgetContent.CollapseSummary)
+								collapseSummary.mCollapseIndex = (.)@entry.Index;
+							val.mLine = entry.mAnchorLine;
+							*valuePtr = val;
+						}
+						else
+							delete val;
 					}
 				}
 
@@ -5432,6 +5967,20 @@ namespace IDE.ui
 			}
         }
 
+		public override void Resize(float x, float y, float width, float height)
+		{
+			base.Resize(x, y, width, height);
+
+			for (var embed in mEmbeds.Values)
+			{
+				if (var emitEmbed = embed as EmitEmbed)
+				{
+					if (emitEmbed.mView != null)
+						emitEmbed.mView.Resize(emitEmbed.mView.mX, emitEmbed.mView.mY, mParent.mWidth - emitEmbed.mView.mX, emitEmbed.mView.mHeight);
+				}
+			}
+		}
+
 		public void CollapseToggle()
 		{
 			CollapseEntry* foundEntry = null;
@@ -5560,10 +6109,13 @@ namespace IDE.ui
 			{
 				if (mEmbeds.GetValue(entry.mAnchorLine) case .Ok(let embed))
 				{
-					if ((embed.mKind == .HideLine) || (embed.mKind == .LineEnd))
+					if (embed is CollapseSummary)
 					{
-						delete embed;
-						mEmbeds.Remove(entry.mAnchorLine);
+						if ((embed.mKind == .HideLine) || (embed.mKind == .LineEnd))
+						{
+							delete embed;
+							mEmbeds.Remove(entry.mAnchorLine);
+						}
 					}
 				}
 			}
@@ -5591,6 +6143,7 @@ namespace IDE.ui
 			}
 		}
 
+
 		public void RefreshCollapseRegion(SourceEditWidgetContent.CollapseEntry* entry, int32 prevAnchorLine, bool failed)
 		{
 			if (failed)
@@ -5605,7 +6158,10 @@ namespace IDE.ui
 				if (mEmbeds.GetAndRemove(prevAnchorLine) case .Ok(let val))
 				{
 					if (mEmbeds.TryAdd(entry.mAnchorLine, var keyPtr, var valuePtr))
+					{
+						val.value.mLine = entry.mAnchorLine;
 						*valuePtr = val.value;
+					}
 					else
 						delete val.value;
 				}
@@ -5685,14 +6241,34 @@ namespace IDE.ui
 
 			var data = PreparedData;
 
-			data.mCollapseData.Clear();
+			data.Clear();
 
 			for (var line in collapseText.Split('\n', .RemoveEmptyEntries))
 			{
 				SourceEditWidgetContent.CollapseEntry.Kind kind = (.)line[0];
 				line.RemoveFromStart(1);
 
+				if (kind == .EmitAddType)
+				{
+					data.mTypeNames.Add(new String(line));
+					continue;
+				}
+
 				var itr = line.Split(',');
+				if (kind.IsEmit)
+				{
+					EmitData emitData;
+					emitData.mKind = kind;
+					emitData.mTypeNameIdx = int32.Parse(itr.GetNext().Value);
+					emitData.mRevision = int32.Parse(itr.GetNext().Value);
+					emitData.mPartialIdx = int32.Parse(itr.GetNext().Value);
+					emitData.mAnchorIdx = int32.Parse(itr.GetNext().Value);
+					emitData.mStartLine = int32.Parse(itr.GetNext().Value);
+					emitData.mEndLine = int32.Parse(itr.GetNext().Value);
+					emitData.mAnchorId = lookupCtx.GetIdAtIndex(emitData.mAnchorIdx);
+					data.mEmitData.Add(emitData);
+					continue;
+				}
 
 				CollapseData collapseData;
 
@@ -5730,6 +6306,7 @@ namespace IDE.ui
 				if (mEmbeds.TryAdd(entry.mAnchorLine, var keyPtr, var valuePtr))
 				{
 					SourceEditWidgetContent.CollapseSummary collapseSummary = new .();
+					collapseSummary.mLine = entry.mAnchorLine;
 					collapseSummary.mEditWidgetContent = this;
 					collapseSummary.mCollapseIndex = (.)collapseIdx;
 					collapseSummary.mKind = .HideLine;
@@ -5774,11 +6351,20 @@ namespace IDE.ui
 				if (mEmbeds.TryAdd(entry.mAnchorLine, var keyPtr, var valuePtr))
 				{
 					SourceEditWidgetContent.CollapseSummary collapseSummary = new .();
+					collapseSummary.mLine = entry.mAnchorLine;
 					collapseSummary.mEditWidgetContent = this;
 					collapseSummary.mCollapseIndex = (.)collapseIdx;
 					collapseSummary.mKind = .LineEnd;
 					*valuePtr = collapseSummary;
 				}
+				else
+				{
+					if (var emitEntry = *valuePtr as EmitEmbed)
+					{
+						emitEntry.mIsOpen = false;
+						mCollapseNeedsUpdate = true;
+					}
+				}
 			}
 		}
 
@@ -5830,8 +6416,44 @@ namespace IDE.ui
 
 			if (animIdx == -1)
 			{
-				RehupLineCoords();
 				mCollapseNeedsUpdate = false;
+
+				for (var embed in mEmbeds.Values)
+				{
+					if (var emitEmbed = embed as EmitEmbed)
+					{
+						if (emitEmbed.mIsOpen)
+						{
+							emitEmbed.mOpenPct = Math.Min(1.0f, emitEmbed.mOpenPct + 0.1f);
+							if (emitEmbed.mOpenPct != 1.0f)
+								mCollapseNeedsUpdate = true;
+
+							if (emitEmbed.mView == null)
+							{
+								mSourceViewPanel.QueueFullRefresh(false);
+								emitEmbed.mView = new SourceEditWidgetContent.EmitEmbed.View(emitEmbed);
+								AddWidget(emitEmbed.mView);
+							}
+						}
+						else
+						{
+							emitEmbed.mOpenPct = Math.Max(0.0f, emitEmbed.mOpenPct - 0.1f);
+							if (emitEmbed.mOpenPct == 0.0f)
+							{
+								if (emitEmbed.mView != null)
+								{
+									emitEmbed.mView.RemoveSelf();
+									DeleteAndNullify!(emitEmbed.mView);
+								}
+							}
+							else
+								mCollapseNeedsUpdate = true;
+						}
+					}
+				}
+
+				RehupLineCoords();
+
 				return;
 			}
 
@@ -5915,6 +6537,5 @@ namespace IDE.ui
 
 			RehupLineCoords(animIdx, animLines);
 		}
-
     }
 }

ファイルの差分が大きいため隠しています
+ 488 - 118
IDE/src/ui/SourceViewPanel.bf


+ 2 - 0
IDE/src/ui/StatusBar.bf

@@ -408,6 +408,8 @@ namespace IDE.ui
 			{
 				DrawStatusBox("Loading Projects");
 			}
+			else if (gApp.mDeferredShowSource != null)
+				DrawStatusBox("Queued Showing Source");
 			else
 				mStatusBoxUpdateCnt = -1;
 

+ 81 - 5
IDEHelper/COFF.cpp

@@ -5,14 +5,18 @@
 #include "DebugTarget.h"
 #include "DebugManager.h"
 #include "DWARFInfo.h"
-#include "BeefySysLib/Util/PerfTimer.h"
-#include "BeefySysLib/Util/Dictionary.h"
-#include "BeefySysLib/Util/BeefPerf.h"
+#include "BeefySysLib/util/PerfTimer.h"
+#include "BeefySysLib/util/Dictionary.h"
+#include "BeefySysLib/util/BeefPerf.h"
+#include "BeefySysLib/util/BeefPerf.h"
+#include "BeefySysLib/util/ZipFile.h"
+#include "BeefySysLib/util/Hash.h"
 #include "BeefySysLib/platform/PlatformHelper.h"
 #include "WinDebugger.h"
 #include "MiniDumpDebugger.h"
 #include "Linker/BlHash.h"
 #include "Backend/BeLibManger.h"
+#include "Compiler/BfUtil.h"
 #include <shlobj.h>
 
 #include "BeefySysLib/util/AllocDebug.h"
@@ -262,6 +266,7 @@ COFF::COFF(DebugTarget* debugTarget) : DbgModule(debugTarget)
 	mPrevScanName = NULL;
 	mProcSymCount = 0;	
 	mCvSrcSrvStream = -1;
+	mCvEmitStream = -1;
 	mIsFastLink = false;
 	mHotThunkCurAddr = 0;
 	mHotThunkDataLeft = 0;
@@ -270,6 +275,7 @@ COFF::COFF(DebugTarget* debugTarget) : DbgModule(debugTarget)
 	mDbgSymRequest = NULL;	
 	mWantsAutoLoadDebugInfo = false;		
 	mPDBLoaded = false;
+	mEmitSourceFile = NULL;
 }
 
 COFF::~COFF()
@@ -3605,8 +3611,17 @@ CvCompileUnit* COFF::ParseCompileUnit(CvModuleInfo* moduleInfo, CvCompileUnit* c
 					GET_INTO(uint, fileTableOfs);
 					
 					const char* fileName = mStringTable.mStrTable + fileTableOfs;
+
+					if ((fileName[0] == '\\') && (fileName[1] == '$'))
+						fileName++;
+
 					DbgSrcFile* srcFile = NULL;
-					if ((fileName[0] == '/') || (fileName[0] == '\\') ||
+
+					if (fileName[0] == '$')
+					{
+						srcFile = AddSrcFile(compileUnit, fileName);
+					}					
+					else if ((fileName[0] == '/') || (fileName[0] == '\\') ||
 						((fileName[0] != 0) && (fileName[1] == ':')))					
 					{
 						srcFile = AddSrcFile(compileUnit, fileName);
@@ -4642,6 +4657,8 @@ void COFF::ScanCompileUnit(int compileUnitId)
 				else
 				{
 					const char* fileName = mStringTable.mStrTable + fileTableOfs;
+					if ((fileName[0] == '\\') && (fileName[1] == '$'))
+						fileName++;
 					srcFile = AddSrcFile(NULL, fileName);
 					mSrcFileDeferredRefs.Add(srcFile);
 					*srcFilePtr = srcFile;
@@ -4967,6 +4984,8 @@ bool COFF::CvParseHeader(uint8 wantGuid[16], int32 wantAge)
 			mStringTable.mStream = streamNum;
 		if (strcmp(tableName, "srcsrv") == 0)
 			mCvSrcSrvStream = streamNum;
+		if (strcmp(tableName, "emit") == 0)
+			mCvEmitStream = streamNum;
 
 		/*if (tableIdx == nameTableIdx)
 		{
@@ -6095,6 +6114,9 @@ void COFF::ClosePDB()
 		delete kv.mValue;
 	mHotLibMap.Clear();	
 	mHotLibSymMap.Clear();
+
+	delete mEmitSourceFile;
+	mEmitSourceFile = NULL;
 }
 
 bool COFF::LoadPDB(const String& pdbPath, uint8 wantGuid[16], int32 wantAge)
@@ -6669,6 +6691,60 @@ String COFF::GetOldSourceCommand(const StringImpl& path)
 	return "";
 }
 
+bool COFF::GetEmitSource(const StringImpl& filePath, String& outText)
+{
+	if (!filePath.StartsWith("$Emit"))
+		return false;
+	
+	if (mEmitSourceFile == NULL)
+	{
+		mEmitSourceFile = new ZipFile();
+
+		String zipPath = mPDBPath;
+		int dotPos = zipPath.LastIndexOf('.');
+		zipPath.RemoveToEnd(dotPos);
+		zipPath.Append("__emit.zip");
+		if (!mEmitSourceFile->Open(zipPath))
+		{
+			if (mCvEmitStream == -1)
+				return "";
+			
+			int outSize;
+			uint8* data = CvReadStream(mCvEmitStream, &outSize);
+						
+			FileStream fileStream;
+			fileStream.Open(zipPath, "wb");
+			fileStream.Write(data, outSize);
+			fileStream.Close();
+
+			delete data;
+
+			mEmitSourceFile->Open(zipPath);
+		}
+	}
+
+	if (mEmitSourceFile->IsOpen())
+	{
+		String usePath = filePath;
+		if (usePath.StartsWith("$Emit"))
+		{
+			int dollarPos = usePath.IndexOf('$', 1);
+			usePath.Remove(0, dollarPos + 1);
+		}		
+		usePath = EncodeFileName(usePath);
+		usePath.Append(".bf");
+
+		Array<uint8> data;
+		if (mEmitSourceFile->Get(usePath, data))
+		{
+			outText.Insert(outText.mLength, (char*)data.mVals, data.mSize);
+			return true;
+		}
+	}
+
+	return false;
+}
+
 bool COFF::HasPendingDebugInfo()
 {
 	if (mDbgSymRequest == NULL)
@@ -7016,7 +7092,7 @@ addr_target COFF::LocateSymbol(const StringImpl& name)
 		delete dbgModule;
 		return 0;
 	}	
-	mDebugger->mDebugTarget->mDbgModules.push_back(dbgModule);
+	mDebugger->mDebugTarget->AddDbgModule(dbgModule);
 
 	auto symbolEntry = mSymbolNameMap.Find(name.c_str());
 	if (symbolEntry != NULL)

+ 4 - 0
IDEHelper/COFF.h

@@ -13,6 +13,7 @@ namespace Beefy
 	class DataStream;
 	class MemStream;
 	class SafeMemStream;
+	class ZipFile;
 }
 
 struct CV_LVAR_ADDR_RANGE;
@@ -214,6 +215,7 @@ public:
 	};
 
 public:	
+	ZipFile* mEmitSourceFile;
 	uint8 mWantPDBGuid[16];
 	int mWantAge;
 
@@ -262,6 +264,7 @@ public:
 	int mCvPublicSymbolInfoStream;
 	int mCvSymbolRecordStream;	
 	int mCvSrcSrvStream;
+	int mCvEmitStream;
 	int mCvNewFPOStream;
 	Array<CvModuleInfo*> mCvModuleInfo;	
 	Dictionary<int, DbgSrcFile*> mCVSrcFileRefCache;
@@ -320,6 +323,7 @@ public:
 	virtual intptr EvaluateLocation(DbgSubprogram* dwSubprogram, const uint8* locData, int locDataLen, WdStackFrame* stackFrame, DbgAddrType* outAddrType, DbgEvalLocFlags flags = DbgEvalLocFlag_None) override;
 	virtual bool CanGetOldSource() override;
 	virtual String GetOldSourceCommand(const StringImpl& path) override;	
+	virtual bool GetEmitSource(const StringImpl& filePath, String& outText) override;
 	virtual bool HasPendingDebugInfo() override;
 	virtual void PreCacheImage() override;
 	virtual void PreCacheDebugInfo() override;

+ 39 - 25
IDEHelper/Compiler/BfAutoComplete.cpp

@@ -276,10 +276,15 @@ int BfAutoComplete::GetCursorIdx(BfAstNode* node)
 	if (node == NULL)
 		return -1;
 
-	if (!node->IsFromParser(mCompiler->mResolvePassData->mParser))
-		return -1;
+// 	if (!node->IsFromParser(mCompiler->mResolvePassData->mParser))
+// 		return -1;
 
+	if (node->IsTemporary())
+		return false;
 	auto bfParser = node->GetSourceData()->ToParser();
+	if (bfParser == NULL)
+		return -1;
+
 	if ((bfParser->mParserFlags & ParserFlag_Autocomplete) == 0)
 		return -1;
 
@@ -291,10 +296,14 @@ bool BfAutoComplete::IsAutocompleteNode(BfAstNode* node, int lengthAdd, int star
 	if (node == NULL)
 		return false;
 	
-	if (!node->IsFromParser(mCompiler->mResolvePassData->mParser))
-		return false;
+// 	if (!node->IsFromParser(mCompiler->mResolvePassData->mParser))
+// 		return false;
 
+	if (node->IsTemporary())
+		return false;
 	auto bfParser = node->GetSourceData()->ToParser();
+	if (bfParser == NULL)
+		return false;
 	if ((bfParser->mParserFlags & ParserFlag_Autocomplete) == 0)
 		return false;
 			
@@ -313,10 +322,14 @@ bool BfAutoComplete::IsAutocompleteNode(BfAstNode* startNode, BfAstNode* endNode
 	if ((startNode == NULL) || (endNode == NULL))
 		return false;
 
-	if (!startNode->IsFromParser(mCompiler->mResolvePassData->mParser))
-		return false;
+// 	if (!startNode->IsFromParser(mCompiler->mResolvePassData->mParser))
+// 		return false;
 
+	if (startNode->IsTemporary())
+		return false;
 	auto bfParser = startNode->GetSourceData()->ToParser();
+	if (bfParser == NULL)
+		return false;
 	if ((bfParser->mParserFlags & ParserFlag_Autocomplete) == 0)
 		return false;
 
@@ -335,10 +348,14 @@ bool BfAutoComplete::IsAutocompleteLineNode(BfAstNode* node)
 	if (node == NULL)
 		return false;
 
-	if (!node->IsFromParser(mCompiler->mResolvePassData->mParser))
-		return false;
+// 	if (!node->IsFromParser(mCompiler->mResolvePassData->mParser))
+// 		return false;
 
+	if (node->IsTemporary())
+		return false;
 	auto bfParser = node->GetSourceData()->ToParser();
+	if (bfParser == NULL)
+		return false;
 	if ((bfParser->mParserFlags & ParserFlag_Autocomplete) == 0)
 		return false;
 
@@ -414,7 +431,7 @@ BfTypedValue BfAutoComplete::LookupTypeRefOrIdentifier(BfAstNode* node, bool* is
 				{
 					// This keeps the classifier from colorizing properties - this causes 'flashing' when we go back over this with a resolve pass
 					//  that wouldn't catch this
-					SetAndRestoreValue<BfSourceClassifier*> prevClassifier(mModule->mCompiler->mResolvePassData->mSourceClassifier, NULL);
+					SetAndRestoreValue<bool> prevClassifier(mModule->mCompiler->mResolvePassData->mIsClassifying, false);
 
 					BfExprEvaluator exprEvaluator(mModule);
 					auto fieldResult = exprEvaluator.LookupField(qualifiedTypeRef->mRight, leftValue, rightNamedTypeRef->mNameNode->ToString());
@@ -1271,11 +1288,17 @@ BfProject* BfAutoComplete::GetActiveProject()
 	auto activeTypeDef = mModule->GetActiveTypeDef();
 	if (activeTypeDef != NULL)
 		bfProject = activeTypeDef->mProject;
-	else
-		bfProject = mCompiler->mResolvePassData->mParser->mProject;
+	else if (!mCompiler->mResolvePassData->mParsers.IsEmpty())
+		bfProject = mCompiler->mResolvePassData->mParsers[0]->mProject;
 	return bfProject;
 }
 
+bool BfAutoComplete::WantsEntries()
+{
+	return (mResolveType == BfResolveType_Autocomplete) || 
+		(mResolveType == BfResolveType_Autocomplete_HighPri);
+}
+
 void BfAutoComplete::AddTopLevelNamespaces(BfAstNode* identifierNode)
 {	
 	String filter;
@@ -1419,8 +1442,8 @@ void BfAutoComplete::AddTopLevelTypes(BfAstNode* identifierNode, bool onlyAttrib
 	else
 	{
 		BfProject* curProject = NULL;
-		if (mModule->mCompiler->mResolvePassData->mParser != NULL)
-			curProject = mModule->mCompiler->mResolvePassData->mParser->mProject;
+		if (!mModule->mCompiler->mResolvePassData->mParsers.IsEmpty())
+			curProject = mModule->mCompiler->mResolvePassData->mParsers[0]->mProject;
 
 		String prevName;
 		for (auto typeDef : mModule->mSystem->mTypeDefs)
@@ -1468,14 +1491,6 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
 			}
 		}
 	}
-
-	//bool isUsingDirective = false;
-	//bool isUsingDirective = (identifierNode != NULL) && (identifierNode->mParent != NULL) && (identifierNode->mParent->IsA<BfUsingDirective>());
-	if (mCompiler->mResolvePassData->mSourceClassifier != NULL)
-	{
-		//TODO: Color around dots
-		//mCompiler->mResolvePassData->mSourceClassifier->SetElementType(identifierNode, BfSourceElementType_Namespace);
-	}
 	
 	if (auto qualifiedNameNode = BfNodeDynCast<BfQualifiedNameNode>(identifierNode))
 	{
@@ -1483,10 +1498,6 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
 		return;
 	}
 
-	//bool isInExpression = true;
-// 	if (identifierNode != NULL)
-// 		isInExpression = IsInExpression(identifierNode);
-	
 	AddTopLevelNamespaces(identifierNode);
 	if (isUsingDirective)
 		return; // Only do namespaces
@@ -1759,6 +1770,9 @@ String BfAutoComplete::GetFilter(BfAstNode* node)
 
 bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken, BfAstNode* memberName, bool onlyShowTypes, BfType* expectingType, bool isUsingDirective, bool onlyAttribute)
 {
+	if (!WantsEntries())
+		return false;
+
 	BfAttributedIdentifierNode* attrIdentifier = NULL;
 	bool isAutocompletingName = false;
 	if ((attrIdentifier = BfNodeDynCast<BfAttributedIdentifierNode>(memberName)))

+ 1 - 0
IDEHelper/Compiler/BfAutoComplete.h

@@ -208,6 +208,7 @@ public:
 
 public:	
 	BfProject* GetActiveProject();
+	bool WantsEntries();
 	bool CheckProtection(BfProtection protection, BfTypeDef* typeDef, bool allowProtected, bool allowPrivate);
 	String GetFilter(BfAstNode* node);
 	const char* GetTypeName(BfType* type);

+ 499 - 118
IDEHelper/Compiler/BfCompiler.cpp

@@ -27,6 +27,7 @@
 #include "BfAutoComplete.h"
 #include "BfResolvePass.h"
 #include "BeefySysLib/util/BeefPerf.h"
+#include "BeefySysLib/util/ZipFile.h"
 #include "../LLVMUtils.h"
 #include "BfNamespaceVisitor.h"
 #include "CeMachine.h"
@@ -2276,7 +2277,7 @@ void BfCompiler::UpdateDependencyMap(bool deleteUnusued, bool& didWork)
 	bool madeFullPass = true;
 	if (mCanceling)
 		madeFullPass = false;
-	if ((mResolvePassData != NULL) && (mResolvePassData->mParser != NULL))
+	if ((mResolvePassData != NULL) && (!mResolvePassData->mParsers.IsEmpty()))
 		madeFullPass = false;
 	
 	SetAndRestoreValue<bool> prevAssertOnPopulateType(mContext->mAssertOnPopulateType, deleteUnusued && madeFullPass);
@@ -3736,19 +3737,19 @@ void BfCompiler::VisitAutocompleteExteriorIdentifiers()
 
 		if (mResolvePassData->mAutoComplete != NULL)
 			mResolvePassData->mAutoComplete->CheckIdentifier(checkIdentifier, false, isUsingDirective);
-
-		if ((checkIdentifier->IsFromParser(mResolvePassData->mParser)) && (mResolvePassData->mSourceClassifier != NULL))
+		
+		if (auto sourceClassifier = mResolvePassData->GetSourceClassifier(checkIdentifier))
 		{
 			if (isUsingDirective)
 			{
 				while (auto qualifiedNameNode = BfNodeDynCast<BfQualifiedNameNode>(checkIdentifier))
 				{
-					mResolvePassData->mSourceClassifier->SetElementType(qualifiedNameNode->mRight, BfSourceElementType_Namespace);
+					sourceClassifier->SetElementType(qualifiedNameNode->mRight, BfSourceElementType_Namespace);
 					checkIdentifier = qualifiedNameNode->mLeft;
 				}
 
 				if (checkIdentifier != NULL)
-					mResolvePassData->mSourceClassifier->SetElementType(checkIdentifier, BfSourceElementType_Namespace);
+					sourceClassifier->SetElementType(checkIdentifier, BfSourceElementType_Namespace);
 			}
 		}
 	}
@@ -3903,9 +3904,10 @@ void BfCompiler::VisitSourceExteriorNodes()
 			parser->mParserData->mExteriorNodesCheckIdx = mSystem->mTypeMapVersion;
 	};
 
-	if ((mResolvePassData != NULL) && (mResolvePassData->mParser != NULL))
+	if (mResolvePassData != NULL)
 	{
-		_CheckParser(mResolvePassData->mParser);
+		for (auto parser : mResolvePassData->mParsers)
+			_CheckParser(parser);
 	}
 	else		
 	{
@@ -3936,18 +3938,21 @@ void BfCompiler::ProcessAutocompleteTempType()
 
 	if (autoComplete->mResolveType == BfResolveType_GetNavigationData)
 	{
-		for (auto node : mResolvePassData->mParser->mSidechannelRootNode->mChildArr)
+		for (auto parser : mResolvePassData->mParsers)
 		{
-			if (auto preprocNode = BfNodeDynCast<BfPreprocessorNode>(node))
+			for (auto node : parser->mSidechannelRootNode->mChildArr)
 			{
-				if (preprocNode->mCommand->Equals("region"))
+				if (auto preprocNode = BfNodeDynCast<BfPreprocessorNode>(node))
 				{
-					if (!autoCompleteResultString.empty())
-						autoCompleteResultString += "\n";
-					autoCompleteResultString += "#";
-					preprocNode->mArgument->ToString(autoCompleteResultString);
-					mContext->mScratchModule->UpdateSrcPos(preprocNode, (BfSrcPosFlags)(BfSrcPosFlag_NoSetDebugLoc | BfSrcPosFlag_Force));
-					autoCompleteResultString += StrFormat("\tregion\t%d\t%d", module->mCurFilePosition.mCurLine, module->mCurFilePosition.mCurColumn);
+					if (preprocNode->mCommand->Equals("region"))
+					{
+						if (!autoCompleteResultString.empty())
+							autoCompleteResultString += "\n";
+						autoCompleteResultString += "#";
+						preprocNode->mArgument->ToString(autoCompleteResultString);
+						mContext->mScratchModule->UpdateSrcPos(preprocNode, (BfSrcPosFlags)(BfSrcPosFlag_NoSetDebugLoc | BfSrcPosFlag_Force));
+						autoCompleteResultString += StrFormat("\tregion\t%d\t%d", module->mCurFilePosition.mCurLine, module->mCurFilePosition.mCurColumn);
+					}
 				}
 			}
 		}
@@ -4041,7 +4046,7 @@ void BfCompiler::ProcessAutocompleteTempType()
 	if (autoComplete->mResolveType == BfResolveType_GetCurrentLocation)
 	{
 		for (auto tempTypeDef : mResolvePassData->mAutoCompleteTempTypes)
-		{						
+		{
 			String typeName = tempTypeDef->mNamespace.ToString();
 			if (!typeName.empty())
 				typeName += ".";
@@ -4049,16 +4054,21 @@ void BfCompiler::ProcessAutocompleteTempType()
 
 			autoCompleteResultString = typeName;
 
-			int cursorPos = mResolvePassData->mParser->mCursorIdx;
-
 			for (auto methodDef : tempTypeDef->mMethods)
 			{	
 				BfAstNode* defNode = methodDef->mMethodDeclaration;
 				if (auto propertyDeclaration = methodDef->GetPropertyDeclaration())
 					defNode = propertyDeclaration;
 
+				if (defNode == NULL)
+					continue;
+
+				auto parser = defNode->GetParser();
+				if ((parser == NULL) || (parser->mCursorIdx == -1))
+					continue;
+
 				if ((defNode != NULL) && 
-					(defNode->Contains(cursorPos)))
+					(defNode->Contains(parser->mCursorIdx)))
 				{
 					String methodText = methodDef->ToString();
 					if (typeName != "@")
@@ -4070,6 +4080,53 @@ void BfCompiler::ProcessAutocompleteTempType()
 			}			
 		}
 
+		if (mResolvePassData->mAutoCompleteTempTypes.IsEmpty())
+		{
+			for (auto& kv : mResolvePassData->mEmitEmbedEntries)
+			{
+				if (kv.mValue.mCursorIdx < 0)
+					continue;
+
+				String typeName = kv.mKey;
+				auto type = GetType(typeName);
+				if (type == NULL)
+					continue;
+				auto typeInst = type->ToTypeInstance();
+				if (typeInst == NULL)
+					continue;
+
+				if (mResolvePassData->mParsers.IsEmpty())
+					break;
+				
+				autoCompleteResultString = mContext->mScratchModule->TypeToString(typeInst);
+
+				for (auto methodDef : typeInst->mTypeDef->mMethods)
+				{					
+					BfAstNode* defNode = methodDef->mMethodDeclaration;
+					if (auto propertyDeclaration = methodDef->GetPropertyDeclaration())
+						defNode = propertyDeclaration;
+
+					if (defNode == NULL)
+						continue;					
+
+					if ((defNode != NULL) &&
+						(defNode->Contains(kv.mValue.mCursorIdx)))
+					{
+						auto defParser = defNode->GetParser();
+						if (defParser == NULL)
+							continue;
+
+						if (!defParser->mIsEmitted)
+							continue;
+						
+						autoCompleteResultString += ".";
+						autoCompleteResultString += methodDef->ToString();						
+						break;
+					}
+				}
+			}
+		}
+
 		module->CleanupFileInstances();
 		return;
 	}
@@ -4094,59 +4151,58 @@ void BfCompiler::ProcessAutocompleteTempType()
 		BfAstNode* conflictStart = NULL;
 		BfAstNode* conflictSplit = NULL;		
 
-		auto src = mResolvePassData->mParser->mSrc;
-
-		for (int checkIdx = 0; checkIdx < (int)mResolvePassData->mParser->mSidechannelRootNode->mChildArr.mSize; checkIdx++)
+		for (auto parser : mResolvePassData->mParsers)
 		{
-			auto sideNode = mResolvePassData->mParser->mSidechannelRootNode->mChildArr.mVals[checkIdx];
-			if (autoComplete->CheckFixit(sideNode))
-			{
-				if (src[sideNode->mSrcStart] == '<')
-				{
-					conflictStart = sideNode;
-					conflictSplit = NULL;
-				}				
-			}
-			else
+			auto src = parser->mSrc;
+
+			for (int checkIdx = 0; checkIdx < (int)parser->mSidechannelRootNode->mChildArr.mSize; checkIdx++)
 			{
-				if (src[sideNode->mSrcStart] == '<')
+				auto sideNode = parser->mSidechannelRootNode->mChildArr.mVals[checkIdx];
+				if (autoComplete->CheckFixit(sideNode))
 				{
-					conflictStart = NULL;
-					conflictSplit = NULL;
-				}
-				else if (src[sideNode->mSrcStart] == '=')
-				{
-					if (conflictStart != NULL)
-						conflictSplit = sideNode;
+					if (src[sideNode->mSrcStart] == '<')
+					{
+						conflictStart = sideNode;
+						conflictSplit = NULL;
+					}
 				}
-				else if (src[sideNode->mSrcStart] == '>')
+				else
 				{
-					if (conflictSplit != NULL)
+					if (src[sideNode->mSrcStart] == '<')
+					{
+						conflictStart = NULL;
+						conflictSplit = NULL;
+					}
+					else if (src[sideNode->mSrcStart] == '=')
 					{
-						autoComplete->AddEntry(AutoCompleteEntry("fixit", StrFormat("Accept First\tdelete|%s-%d|\x01""delete|%s-%d|",
-							autoComplete->FixitGetLocation(mResolvePassData->mParser->mParserData, conflictSplit->mSrcStart).c_str(), sideNode->mSrcEnd - conflictSplit->mSrcStart + 1,
-							autoComplete->FixitGetLocation(mResolvePassData->mParser->mParserData, conflictStart->mSrcStart).c_str(), conflictStart->mSrcEnd - conflictStart->mSrcStart + 1).c_str()));
+						if (conflictStart != NULL)
+							conflictSplit = sideNode;
+					}
+					else if (src[sideNode->mSrcStart] == '>')
+					{
+						if (conflictSplit != NULL)
+						{
+							autoComplete->AddEntry(AutoCompleteEntry("fixit", StrFormat("Accept First\tdelete|%s-%d|\x01""delete|%s-%d|",
+								autoComplete->FixitGetLocation(parser->mParserData, conflictSplit->mSrcStart).c_str(), sideNode->mSrcEnd - conflictSplit->mSrcStart + 1,
+								autoComplete->FixitGetLocation(parser->mParserData, conflictStart->mSrcStart).c_str(), conflictStart->mSrcEnd - conflictStart->mSrcStart + 1).c_str()));
 
-						autoComplete->AddEntry(AutoCompleteEntry("fixit", StrFormat("Accept Second\tdelete|%s-%d|\x01""delete|%s-%d|",
-							autoComplete->FixitGetLocation(mResolvePassData->mParser->mParserData, sideNode->mSrcStart).c_str(), sideNode->mSrcEnd - sideNode->mSrcStart + 1,
-							autoComplete->FixitGetLocation(mResolvePassData->mParser->mParserData, conflictStart->mSrcStart).c_str(), conflictSplit->mSrcEnd - conflictStart->mSrcStart + 1).c_str()));
+							autoComplete->AddEntry(AutoCompleteEntry("fixit", StrFormat("Accept Second\tdelete|%s-%d|\x01""delete|%s-%d|",
+								autoComplete->FixitGetLocation(parser->mParserData, sideNode->mSrcStart).c_str(), sideNode->mSrcEnd - sideNode->mSrcStart + 1,
+								autoComplete->FixitGetLocation(parser->mParserData, conflictStart->mSrcStart).c_str(), conflictSplit->mSrcEnd - conflictStart->mSrcStart + 1).c_str()));
 
-						autoComplete->AddEntry(AutoCompleteEntry("fixit", StrFormat("Accept Both\tdelete|%s-%d|\x01""delete|%s-%d|\x01""delete|%s-%d|",
-							autoComplete->FixitGetLocation(mResolvePassData->mParser->mParserData, sideNode->mSrcStart).c_str(), sideNode->mSrcEnd - sideNode->mSrcStart + 1,
-							autoComplete->FixitGetLocation(mResolvePassData->mParser->mParserData, conflictSplit->mSrcStart).c_str(), conflictSplit->mSrcEnd - conflictSplit->mSrcStart + 1,
-							autoComplete->FixitGetLocation(mResolvePassData->mParser->mParserData, conflictStart->mSrcStart).c_str(), conflictStart->mSrcEnd - conflictStart->mSrcStart + 1).c_str()));
+							autoComplete->AddEntry(AutoCompleteEntry("fixit", StrFormat("Accept Both\tdelete|%s-%d|\x01""delete|%s-%d|\x01""delete|%s-%d|",
+								autoComplete->FixitGetLocation(parser->mParserData, sideNode->mSrcStart).c_str(), sideNode->mSrcEnd - sideNode->mSrcStart + 1,
+								autoComplete->FixitGetLocation(parser->mParserData, conflictSplit->mSrcStart).c_str(), conflictSplit->mSrcEnd - conflictSplit->mSrcStart + 1,
+								autoComplete->FixitGetLocation(parser->mParserData, conflictStart->mSrcStart).c_str(), conflictStart->mSrcEnd - conflictStart->mSrcStart + 1).c_str()));
 
-						conflictStart = NULL;
-						conflictSplit = NULL;
+							conflictStart = NULL;
+							conflictSplit = NULL;
+						}
 					}
 				}
 			}
 		}
 
-		for (auto sideNode : mResolvePassData->mParser->mSidechannelRootNode->mChildArr)
-		{
-			
-		}
 	}
 
 	if (autoComplete->mResolveType == BfResolveType_GetSymbolInfo)
@@ -4154,7 +4210,8 @@ void BfCompiler::ProcessAutocompleteTempType()
 		BfNamespaceVisitor namespaceVisitor;
 		namespaceVisitor.mResolvePassData = mResolvePassData;
 		namespaceVisitor.mSystem = mSystem;
-		namespaceVisitor.Visit(mResolvePassData->mParser->mRootNode);
+		for (auto parser : mResolvePassData->mParsers)
+			namespaceVisitor.Visit(parser->mRootNode);
 	}
 	
 	auto _FindAcutalTypeDef = [&](BfTypeDef* tempTypeDef)
@@ -4204,6 +4261,9 @@ void BfCompiler::ProcessAutocompleteTempType()
 			mContext->HandleChangedTypeDef(checkTempType, true);
 		}
 
+		auto sourceClassifier = mResolvePassData->GetSourceClassifier(checkTempType->mTypeDeclaration->mNameNode);
+		if (sourceClassifier == NULL)
+			continue;
 		BfSourceElementType elemType = BfSourceElementType_Type;
 		if (checkTempType->mTypeCode == BfTypeCode_Interface)
 			elemType = BfSourceElementType_Interface;
@@ -4211,11 +4271,32 @@ void BfCompiler::ProcessAutocompleteTempType()
 			elemType = BfSourceElementType_RefType;
 		else if (checkTempType->mTypeCode == BfTypeCode_Struct)
 			elemType = BfSourceElementType_Struct;
-		mResolvePassData->mSourceClassifier->SetElementType(checkTempType->mTypeDeclaration->mNameNode, elemType);
+		sourceClassifier->SetElementType(checkTempType->mTypeDeclaration->mNameNode, elemType);
 	}
 
 	if (tempTypeDef == NULL)
 	{
+		if ((autoComplete != NULL) && (autoComplete->mResolveType == BfResolveType_GoToDefinition))
+		{
+			for (auto& kv : mResolvePassData->mEmitEmbedEntries)
+			{
+				String typeName = kv.mKey;
+				auto type = GetType(typeName);
+				if (type == NULL)
+					continue;
+				auto typeInst = type->ToTypeInstance();
+				if (typeInst == NULL)
+					continue;
+
+				mContext->RebuildType(typeInst);
+				if (!typeInst->mModule->mIsModuleMutable)
+					typeInst->mModule->StartNewRevision(BfModule::RebuildKind_All, true);
+				mContext->mScratchModule->PopulateType(typeInst, Beefy::BfPopulateType_Full_Force);
+			}
+
+			DoWorkLoop();
+		}
+
 		GenerateAutocompleteInfo();
 		BfLogSysM("ProcessAutocompleteTempType - no tempTypeDef\n");
 		return;
@@ -4319,10 +4400,11 @@ void BfCompiler::ProcessAutocompleteTempType()
 		return;
 	}
 	
+	auto sourceClassifier = mResolvePassData->GetSourceClassifier(tempTypeDef->mTypeDeclaration);
 	if (tempTypeDef->mTypeCode == BfTypeCode_Extension)
-		mResolvePassData->mSourceClassifier->SetElementType(tempTypeDef->mTypeDeclaration->mNameNode, actualTypeDef->mTypeCode);
+		sourceClassifier->SetElementType(tempTypeDef->mTypeDeclaration->mNameNode, actualTypeDef->mTypeCode);
 	if (tempTypeDef->mTypeDeclaration->mAttributes != NULL)
-		mResolvePassData->mSourceClassifier->VisitChild(tempTypeDef->mTypeDeclaration->mAttributes);
+		sourceClassifier->VisitChild(tempTypeDef->mTypeDeclaration->mAttributes);
 
 	BfTypeInstance* typeInst;
 	{
@@ -4750,10 +4832,16 @@ BfType* BfCompiler::CheckSymbolReferenceTypeRef(BfModule* module, BfTypeReferenc
 
 void BfCompiler::AddToRebuildTypeList(BfTypeInstance* typeInst, HashSet<BfTypeInstance*>& rebuildTypeInstList)
 {
-	if (mResolvePassData->mParser != NULL)
+	if (!mResolvePassData->mParsers.IsEmpty())
 	{
-		// Only find references within the current file
-		if (!typeInst->mTypeDef->GetDefinition()->HasSource(mResolvePassData->mParser))
+		bool found = false;
+		for (auto parser : mResolvePassData->mParsers)
+		{
+			// Only find references within the current file
+			if (typeInst->mTypeDef->GetDefinition()->HasSource(parser))
+				found = true;
+		}
+		if (!found)
 			return;
 	}
 
@@ -4922,7 +5010,17 @@ void BfCompiler::GetSymbolReferences()
 				for (auto checkTypeDef : typeDef->mPartials)
 				{
 					auto nameNode = checkTypeDef->mTypeDeclaration->mNameNode;
-					if ((mResolvePassData->mParser == NULL) || (nameNode->IsFromParser(mResolvePassData->mParser)))
+
+					for (auto parser : mResolvePassData->mParsers)
+					{
+						if (nameNode->IsFromParser(parser))
+						{							
+							mResolvePassData->HandleTypeReference(nameNode, typeDef);
+							break;
+						}
+					}
+
+					if (mResolvePassData->mParsers.IsEmpty())
 						mResolvePassData->HandleTypeReference(nameNode, typeDef);
 
 					if (checkTypeDef->IsExtension())
@@ -5365,9 +5463,7 @@ bool BfCompiler::IsDataResolvePass()
 
 bool BfCompiler::WantsClassifyNode(BfAstNode* node)
 {
-	return ((mResolvePassData != NULL) &&
-		(node->IsFromParser(mResolvePassData->mParser)) &&
-		(mResolvePassData->mSourceClassifier != NULL));
+	return (mResolvePassData != NULL) && (mResolvePassData->GetSourceClassifier(node) != NULL);		
 }
 
 BfAutoComplete* BfCompiler::GetAutoComplete()
@@ -6673,7 +6769,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	mHasComptimeRebuilds = false;
 	int revision = mRevision;
 	BfLogSysM("Compile Start. Revision: %d. HasParser:%d AutoComplete:%d\n", revision, 
-		(mResolvePassData != NULL) && (mResolvePassData->mParser != NULL), 
+		(mResolvePassData != NULL) && (!mResolvePassData->mParsers.IsEmpty()), 
 		(mResolvePassData != NULL) && (mResolvePassData->mAutoComplete != NULL));
 
 	if (mOptions.mCompileOnDemandKind == BfCompileOnDemandKind_AlwaysInclude)
@@ -6785,7 +6881,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	BfTypeDef* typeDef;						
 
 	BfLogSysM("UpdateRevisedTypes Revision %d. ResolvePass:%d CursorIdx:%d\n", mRevision, mIsResolveOnly, 
-		((mResolvePassData == NULL) || (mResolvePassData->mParser == NULL)) ? - 1 : mResolvePassData->mParser->mCursorIdx);	
+		((mResolvePassData == NULL) || (mResolvePassData->mParsers.IsEmpty())) ? - 1 : mResolvePassData->mParsers[0]->mCursorIdx);
 	
 	mCompileState = CompileState_Normal;
 	UpdateRevisedTypes();	
@@ -7455,7 +7551,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 		}
 		else
 		{
-			bool isTargeted = (mResolvePassData != NULL) && (mResolvePassData->mParser != NULL);
+			bool isTargeted = (mResolvePassData != NULL) && (!mResolvePassData->mParsers.IsEmpty());
 			if (!isTargeted)
 			{				
 				for (auto bfModule : mContext->mModules)
@@ -7477,7 +7573,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	//CompileLog("%d object files written: %s\n", numModulesWritten, moduleListStr.c_str());
 	
 	//printf("Compile done, waiting for finish\n");
-
+	
 	while (true)
 	{		
 		if (mCanceling)
@@ -7543,7 +7639,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 		libManager->mErrors.Clear();
 	}
 #endif		
-
+	
 	int numObjFilesWritten = 0;
 	for (auto& fileEntry : mCodeGen.mCodeGenFiles)
 	{
@@ -7588,7 +7684,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 
 	String compileInfo;
 	if (mIsResolveOnly)
-		compileInfo += StrFormat("ResolveOnly ResolveType:%d Parser:%d\n", mResolvePassData->mResolveType, mResolvePassData->mParser != NULL);
+		compileInfo += StrFormat("ResolveOnly ResolveType:%d Parser:%d\n", mResolvePassData->mResolveType, !mResolvePassData->mParsers.IsEmpty());
 	compileInfo += StrFormat("TotalTypes:%d\nTypesPopulated:%d\nMethodsDeclared:%d\nMethodsProcessed:%d\nCanceled? %d\n", mStats.mTotalTypes, mStats.mTypesPopulated, mStats.mMethodDeclarations, mStats.mMethodsProcessed, mCanceling);
 	compileInfo += StrFormat("TypesPopulated:%d\n", mStats.mTypesPopulated);
 	compileInfo += StrFormat("MethodDecls:%d\nMethodsProcessed:%d\nModulesStarted:%d\nModulesFinished:%d\n", mStats.mMethodDeclarations, mStats.mMethodsProcessed, mStats.mModulesFinished);
@@ -7854,8 +7950,11 @@ void BfCompiler::GenerateAutocompleteInfo()
 
 			if (autoComplete->mInsertEndIdx > 0)
 			{
-				if (mResolvePassData->mParser->mSrc[autoComplete->mInsertEndIdx - 1] == '!')
-					autoComplete->mInsertEndIdx--;
+				if (!mResolvePassData->mParsers.IsEmpty())
+				{
+					if (mResolvePassData->mParsers[0]->mSrc[autoComplete->mInsertEndIdx - 1] == '!')
+						autoComplete->mInsertEndIdx--;
+				}
 			}
 		}
 
@@ -9065,17 +9164,75 @@ String BfCompiler::GetTypeDefInfo(const StringImpl& inTypeName)
 	return result;
 }
 
+int BfCompiler::GetTypeId(const StringImpl& typeName)
+{	
+	auto type = GetType(typeName);
+	if (type != NULL)
+		return type->mTypeId;
+	return -1;
+}
+
+BfType* BfCompiler::GetType(const StringImpl& fullTypeName)
+{
+	AutoCrit autoCrit(mSystem->mSystemLock);
+
+	BfPassInstance passInstance(mSystem);
+
+	BfProject* activeProject = NULL;
+	
+	String typeName = fullTypeName;
+	int colonPos = (int)typeName.IndexOf(':');
+	if (colonPos != -1)
+	{
+		activeProject = mSystem->GetProject(typeName.Substring(0, colonPos));
+		typeName.Remove(0, colonPos + 1);
+	}
+
+	BfTypeState typeState;
+	typeState.mPrevState = mContext->mCurTypeState;
+	typeState.mActiveProject = activeProject;
+	SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
+
+	BfParser parser(mSystem);
+	parser.SetSource(typeName.c_str(), (int)typeName.length());
+	parser.Parse(&passInstance);
+
+	BfReducer reducer;
+	reducer.mAlloc = parser.mAlloc;
+	reducer.mPassInstance = &passInstance;
+
+	if (parser.mRootNode->mChildArr.mSize == 0)
+		return NULL;
+
+	auto firstNode = parser.mRootNode->mChildArr[0];
+	auto endIdx = parser.mRootNode->mSrcEnd;
+	reducer.mVisitorPos = BfReducer::BfVisitorPos(parser.mRootNode);
+
+	reducer.mVisitorPos.MoveNext();
+	auto typeRef = reducer.CreateTypeRef(firstNode);
+	if (typeRef == NULL)
+		return NULL;
+
+	BfResolvePassData resolvePass;
+	SetAndRestoreValue<bool> prevIgnoreError(mContext->mScratchModule->mIgnoreErrors, true);
+	SetAndRestoreValue<bool> prevIgnoreWarnings(mContext->mScratchModule->mIgnoreWarnings, true);
+	SetAndRestoreValue<BfResolvePassData*> prevResolvePass(mResolvePassData, &resolvePass);
+
+	auto type = mContext->mScratchModule->ResolveTypeRef(typeRef, BfPopulateType_Identity, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoCreate | BfResolveTypeRefFlag_AllowUnboundGeneric));
+	if (type != NULL)
+		return type;
+
+	return NULL;
+}
+
 int BfCompiler::GetEmitSource(const StringImpl& fileName, StringImpl* outBuffer)
 {	
 	int lastDollarPos = (int)fileName.LastIndexOf('$');
 	if (lastDollarPos == -1)
 		return -1;	
-	int dotPos = (int)fileName.LastIndexOf('.');
-	if (dotPos == -1)
-		return -1;
 	
-	String typeIdStr = fileName.Substring(lastDollarPos + 1, dotPos - lastDollarPos - 1);	
-	int typeId = (int)atoi(typeIdStr.c_str());
+	String typeName = fileName.Substring(lastDollarPos + 1);	
+	int typeId = GetTypeId(typeName);
 	if ((typeId <= 0) || (typeId >= mContext->mTypes.mSize))
 		return -1;
 
@@ -9097,6 +9254,96 @@ int BfCompiler::GetEmitSource(const StringImpl& fileName, StringImpl* outBuffer)
 	return typeInst->mRevision;
 }
 
+String BfCompiler::GetEmitLocation(const StringImpl& typeName, int emitLine, int& outEmbedLine, int& outEmbedLineChar)
+{
+	outEmbedLine = 0;
+
+	int typeId = GetTypeId(typeName);
+	if (typeId <= 0)
+		return "";
+
+	auto bfType = mContext->FindTypeById(typeId);
+	if (bfType == NULL)
+		return "";
+
+	auto typeInst = bfType->ToTypeInstance();
+	if (typeInst == NULL)
+		return "";
+
+	if (typeInst->mCeTypeInfo == NULL)
+		return "";
+
+	for (auto& kv : typeInst->mCeTypeInfo->mEmitSourceMap)
+	{
+		int partialIdx = (int)(kv.mKey >> 32);
+		int charIdx = (int)(kv.mKey & 0xFFFFFFFF);
+
+		auto typeDef = typeInst->mTypeDef;
+		if (partialIdx > 0)
+			typeDef = typeDef->mPartials[partialIdx];
+
+		auto origParser = typeDef->GetDefinition()->GetLastSource()->ToParser();
+		if (origParser == NULL)
+			continue;
+
+		auto emitParser = typeInst->mTypeDef->GetLastSource()->ToParser();
+		if (emitParser == NULL)
+			continue;
+
+		int startLine = 0;
+		int startLineChar = 0;
+		emitParser->GetLineCharAtIdx(kv.mValue.mSrcStart, startLine, startLineChar);
+
+		int endLine = 0;
+		int endLineChar = 0;
+		emitParser->GetLineCharAtIdx(kv.mValue.mSrcEnd - 1, endLine, endLineChar);
+
+		if ((emitLine >= startLine) && (emitLine <= endLine))
+		{			
+			origParser->GetLineCharAtIdx(charIdx, outEmbedLine, outEmbedLineChar);
+			return origParser->mFileName;
+		}
+	}
+
+	return "";
+}
+
+bool BfCompiler::WriteEmitData(const StringImpl& filePath, BfProject* project)
+{
+	ZipFile zipFile;
+
+	for (auto type : mContext->mResolvedTypes)
+	{
+		auto typeInst = type->ToTypeInstance();
+		if (typeInst == NULL)
+			continue;
+		if (typeInst->mTypeDef->mEmitParent == NULL)
+			continue;
+		if (!project->ContainsReference(typeInst->mTypeDef->mProject))
+			continue;
+
+		auto bfParser = typeInst->mTypeDef->GetLastSource()->ToParser();
+		String name = bfParser->mFileName;
+		if (name.StartsWith("$Emit$"))
+			name.Remove(0, 6);
+		String path = EncodeFileName(name);
+		path.Append(".bf");
+
+		if (!zipFile.IsOpen())
+		{
+			if (!zipFile.Create(filePath))
+				return false;
+		}
+
+		zipFile.Add(path, Span<uint8>((uint8*)bfParser->mSrc, bfParser->mSrcLength));
+	}
+
+	if (zipFile.IsOpen())
+		return zipFile.Close();
+
+	return true;
+}
+
 //////////////////////////////////////////////////////////////////////////
 
 PerfManager* BfGetPerfManager(BfParser* bfParser);
@@ -9122,57 +9369,33 @@ BF_EXPORT void BF_CALLTYPE BfCompiler_ClearResults(BfCompiler* bfCompiler)
 	bfCompiler->ClearResults();
 }
 
-BF_EXPORT bool BF_CALLTYPE BfCompiler_ClassifySource(BfCompiler* bfCompiler, BfPassInstance* bfPassInstance, BfParser* bfParser, BfResolvePassData* resolvePassData, BfSourceClassifier::CharData* charData)
+BF_EXPORT bool BF_CALLTYPE BfCompiler_ClassifySource(BfCompiler* bfCompiler, BfPassInstance* bfPassInstance, BfResolvePassData* resolvePassData)
 {
 	BP_ZONE("BfCompiler_ClassifySource");	
-	BfSourceClassifier bfSourceClassifier(bfParser, charData);
-	bfSourceClassifier.mClassifierPassId = bfPassInstance->mClassifierPassId;
 	
 	String& autoCompleteResultString = *gTLStrReturn.Get();
 	autoCompleteResultString.clear();
-
-	bool doClassifyPass = (charData != NULL) && (resolvePassData->mResolveType <= BfResolveType_Autocomplete_HighPri); 
-	bfSourceClassifier.mEnabled = doClassifyPass;
-
-	// Full classifier pass?
 	
-	bfSourceClassifier.mSkipMethodInternals = true;	
-	bfSourceClassifier.mSkipTypeDeclarations = true;	
-	if (charData != NULL)
-	{
-		resolvePassData->mSourceClassifier = &bfSourceClassifier;
-		if (doClassifyPass)
-			bfSourceClassifier.Visit(bfParser->mRootNode);
-	}
-	bfSourceClassifier.mSkipTypeDeclarations = false;
-	bfSourceClassifier.mSkipMethodInternals = false;		
-
-	bfPassInstance->mFilterErrorsTo = bfParser;
+	bfPassInstance->mCompiler = bfCompiler;
+	for (auto parser : resolvePassData->mParsers)
+		bfPassInstance->mFilterErrorsTo.Add(parser->mSourceData);	
 	bfPassInstance->mTrimMessagesToCursor = true;
+
 	SetAndRestoreValue<BfResolvePassData*> prevCompilerResolvePassData(bfCompiler->mResolvePassData, resolvePassData);
 	SetAndRestoreValue<BfPassInstance*> prevPassInstance(bfCompiler->mPassInstance, bfPassInstance);
 	bool canceled = false;
-	if (resolvePassData->mAutoComplete != NULL)
-	{		
+	
+	if ((resolvePassData->mAutoComplete != NULL) && (!resolvePassData->mParsers.IsEmpty()))
+	{
 		bfCompiler->ProcessAutocompleteTempType();
 	}
 	else
-		canceled = !bfCompiler->Compile("");	
-	resolvePassData->mSourceClassifier = NULL;
+		canceled = !bfCompiler->Compile("");
 		
-	if ((charData != NULL) && (doClassifyPass))
-	{
-		bfSourceClassifier.mIsSideChannel = false;
-		bfSourceClassifier.Visit(bfParser->mErrorRootNode);
-
-		bfSourceClassifier.mIsSideChannel = true;
-		bfSourceClassifier.Visit(bfParser->mSidechannelRootNode);				
-	}
-
 	return !canceled;
 }
 
-BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetCollapseRegions(BfCompiler* bfCompiler, BfParser* bfParser)
+BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetCollapseRegions(BfCompiler* bfCompiler, BfParser* bfParser, BfResolvePassData* resolvePassData, char* explicitEmitTypeNames)
 {
 	String& outString = *gTLStrReturn.Get();
 	outString.Clear();
@@ -9515,6 +9738,112 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetCollapseRegions(BfCompiler* bfCo
 
 	collapseVisitor.FlushSeries();
 
+	Array<BfTypeInstance*> explicitEmitTypes;
+	String checkStr = explicitEmitTypeNames;
+	for (auto& typeName : checkStr.Split('\n'))
+	{
+		if (typeName.IsEmpty())
+			continue;
+		auto bfType = bfCompiler->GetType(typeName);
+		if ((bfType != NULL) && (bfType->IsTypeInstance()))
+			explicitEmitTypes.Add(bfType->ToTypeInstance());
+	}
+
+	// Embed emit info
+	BfPassInstance bfPassInstance(bfCompiler->mSystem);
+
+	SetAndRestoreValue<BfResolvePassData*> prevCompilerResolvePassData(bfCompiler->mResolvePassData, resolvePassData);
+	SetAndRestoreValue<BfPassInstance*> prevPassInstance(bfCompiler->mPassInstance, &bfPassInstance);
+
+	Dictionary<int, int> foundTypeIds;
+
+	for (auto typeDef : bfParser->mTypeDefs)
+	{
+		auto useTypeDef = typeDef;
+		if (useTypeDef->mIsPartial)
+		{
+			useTypeDef = bfCompiler->mSystem->GetCombinedPartial(useTypeDef);
+			if (useTypeDef == NULL)
+				continue;
+		}
+
+		auto type = bfCompiler->mContext->mScratchModule->ResolveTypeDef(useTypeDef);
+		if (type == NULL)
+			continue;
+		if (auto typeInst = type->ToTypeInstance())
+		{
+			auto origTypeInst = typeInst;
+
+			if (typeInst->mCeTypeInfo == NULL)
+				continue;
+			
+			for (auto checkIdx = explicitEmitTypes.mSize - 1; checkIdx >= 0; checkIdx--)
+			{
+				auto checkType = explicitEmitTypes[checkIdx];
+				if (checkType->mTypeDef->GetDefinition()->GetLatest() == typeInst->mTypeDef->GetDefinition()->GetLatest())
+				{
+					typeInst = checkType;
+					bfCompiler->mContext->mScratchModule->PopulateType(typeInst);
+					break;
+				}
+			}
+
+			for (auto& kv : typeInst->mCeTypeInfo->mEmitSourceMap)
+			{
+				int partialIdx = (int)(kv.mKey >> 32);
+				int charIdx = (int)(kv.mKey & 0xFFFFFFFF);
+
+				auto typeDef = typeInst->mTypeDef;
+				if (partialIdx > 0)
+					typeDef = typeDef->mPartials[partialIdx];
+
+				auto parser = typeDef->GetDefinition()->GetLastSource()->ToParser();
+				if (parser == NULL)
+					continue;
+
+				if (!FileNameEquals(parser->mFileName, bfParser->mFileName))
+					continue;
+				
+				auto emitParser = typeInst->mTypeDef->GetLastSource()->ToParser();
+				if (emitParser == NULL)
+					continue;
+
+				int startLine = 0;
+				int startLineChar = 0;
+				emitParser->GetLineCharAtIdx(kv.mValue.mSrcStart, startLine, startLineChar);
+
+				int srcEnd = kv.mValue.mSrcEnd - 1;
+				while (srcEnd >= kv.mValue.mSrcStart)
+				{
+					char c = emitParser->mSrc[srcEnd];
+					if (!::isspace((uint8)c))
+						break;
+					srcEnd--;
+				}
+
+				int endLine = 0;
+				int endLineChar = 0;
+				emitParser->GetLineCharAtIdx(srcEnd, endLine, endLineChar);
+				
+				int dollarPos = (int)emitParser->mFileName.LastIndexOf('$');
+				if (dollarPos == -1)
+					continue;
+
+				int* keyPtr = NULL;
+				int* valuePtr = NULL;
+				if (foundTypeIds.TryAdd(typeInst->mTypeId, &keyPtr, &valuePtr))
+				{
+					*valuePtr = foundTypeIds.mCount - 1;
+					outString += "+";
+					outString += emitParser->mFileName.Substring(dollarPos + 1);
+					outString += "\n";
+				}
+
+				outString += (kv.mValue.mKind == BfCeTypeEmitSourceKind_Method) ? 'm' : 't';
+				outString += StrFormat("%d,%d,%d,%d,%d,%d\n", *valuePtr, typeInst->mRevision, partialIdx, charIdx, startLine, endLine + 1);
+			}
+		}
+	}
 	
 	return outString.c_str();
 }
@@ -9587,7 +9916,7 @@ BF_EXPORT bool BF_CALLTYPE BfCompiler_VerifyTypeName(BfCompiler* bfCompiler, cha
 		resolvePassData.mAutoComplete->mCompiler = bfCompiler;
 		resolvePassData.mAutoComplete->mModule = bfCompiler->mContext->mScratchModule;
 	}
-	resolvePassData.mParser = &parser;
+	resolvePassData.mParsers.Add(&parser);
 			
 	SetAndRestoreValue<BfResolvePassData*> prevCompilerResolvePassData(bfCompiler->mResolvePassData, &resolvePassData);
 	SetAndRestoreValue<BfPassInstance*> prevPassInstance(bfCompiler->mPassInstance, &passInstance);
@@ -9733,6 +10062,11 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetTypeDefInfo(BfCompiler* bfCompil
 	return outString.c_str();
 }
 
+BF_EXPORT int BF_CALLTYPE BfCompiler_GetTypeId(BfCompiler* bfCompiler, const char* name)
+{
+	return bfCompiler->GetTypeId(name);	
+}
+
 BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetTypeInfo(BfCompiler* bfCompiler, const char* name)
 {
 	String& outString = *gTLStrReturn.Get();
@@ -9820,6 +10154,40 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetTypeInfo(BfCompiler* bfCompiler,
 	return outString.c_str();
 }
 
+BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetGenericTypeInstances(BfCompiler* bfCompiler, const char* typeName)
+{
+	String& outString = *gTLStrReturn.Get();
+	outString = "";
+
+	auto lookupType = bfCompiler->GetType(typeName);
+	if (lookupType == NULL)
+		return "";
+
+	auto lookupTypeInst = lookupType->ToTypeInstance();
+	if (lookupTypeInst == NULL)
+		return "";
+
+	for (auto type : bfCompiler->mContext->mResolvedTypes)
+	{
+		auto typeInst = type->ToTypeInstance();
+		if (typeInst == NULL)
+			continue;
+
+		if (typeInst->IsUnspecializedTypeVariation())
+			continue;
+
+		if (typeInst->mTypeDef->GetDefinition()->GetLatest() == lookupTypeInst->mTypeDef->GetDefinition()->GetLatest())
+		{
+			outString += typeInst->mTypeDef->mProject->mName;
+			outString += ":";
+			outString += bfCompiler->mContext->mScratchModule->TypeToString(typeInst, BfTypeNameFlags_None);
+			outString += "\n";
+		}
+	}
+
+	return outString.c_str();
+}
+
 enum BfUsedOutputFlags
 {
 	BfUsedOutputFlags_None = 0,
@@ -10236,3 +10604,16 @@ BF_EXPORT int32 BF_CALLTYPE BfCompiler_GetEmitSourceVersion(BfCompiler* bfCompil
 {
 	return bfCompiler->GetEmitSource(fileName, NULL);
 }
+
+BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetEmitLocation(BfCompiler* bfCompiler, char* typeName, int line, int& outEmbedLine, int& outEmbedLineChar)
+{
+	String& outString = *gTLStrReturn.Get();
+	outString.clear();
+	outString = bfCompiler->GetEmitLocation(typeName, line, outEmbedLine, outEmbedLineChar);
+	return outString.c_str();
+}
+
+BF_EXPORT bool BF_CALLTYPE BfCompiler_WriteEmitData(BfCompiler* bfCompiler, char* filePath, BfProject* project)
+{
+	return bfCompiler->WriteEmitData(filePath, project);
+}

+ 4 - 0
IDEHelper/Compiler/BfCompiler.h

@@ -543,7 +543,11 @@ public:
 	String GetTypeDefMatches(const StringImpl& searchSrc);	
 	void GetTypeDefs(const StringImpl& typeName, Array<BfTypeDef*>& typeDefs);
 	String GetTypeDefInfo(const StringImpl& typeName);	
+	int GetTypeId(const StringImpl& typeName);
+	BfType* GetType(const StringImpl& typeName);
 	int GetEmitSource(const StringImpl& fileName, StringImpl* outBuffer);
+	String GetEmitLocation(const StringImpl& typeName, int line, int& outEmbedLine, int& outEmbedLineChar);
+	bool WriteEmitData(const StringImpl& filePath, BfProject* project);
 
 	void CompileLog(const char* fmt ...);
 	void ReportMemory(MemReporter* memReporter);

+ 20 - 12
IDEHelper/Compiler/BfContext.cpp

@@ -355,8 +355,8 @@ bool BfContext::ProcessWorkList(bool onlyReifiedTypes, bool onlyReifiedMethods)
 	while (!mCompiler->mCanceling)
 	{		
 		BfParser* resolveParser = NULL;
-		if (mCompiler->mResolvePassData != NULL)
-			resolveParser = mCompiler->mResolvePassData->mParser;
+		if ((mCompiler->mResolvePassData != NULL) && (!mCompiler->mResolvePassData->mParsers.IsEmpty()))
+			resolveParser = mCompiler->mResolvePassData->mParsers[0];
 
 		bool didWork = false;				
 		
@@ -549,8 +549,16 @@ bool BfContext::ProcessWorkList(bool onlyReifiedTypes, bool onlyReifiedMethods)
 
 				BF_ASSERT(!module->mAwaitingFinish);
 				if ((resolveParser != NULL) && (methodInstance->mMethodDef->mDeclaringType != NULL) && (methodInstance->mMethodDef->mDeclaringType->GetDefinition()->mSource != resolveParser))
-				{					
-					continue;
+				{
+					bool allow = false;
+					if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mHasCursorIdx))
+					{
+						auto parser = methodInstance->mMethodDef->mDeclaringType->GetLastSource()->ToParser();
+						if ((parser != NULL) && (parser->mCursorIdx >= 0))
+							allow = true;
+					}
+					if (!allow)
+						continue;
 				}
 				
 				hasBeenProcessed = methodInstance->mHasBeenProcessed;
@@ -722,7 +730,7 @@ bool BfContext::ProcessWorkList(bool onlyReifiedTypes, bool onlyReifiedMethods)
 				BP_ZONE("PWL_CheckIncompleteGenerics");				
 
 				for (auto type : mResolvedTypes)
-				{					
+				{
 					if ((type->IsIncomplete()) && (type->HasBeenReferenced()))
 					{
 						// The only reason a type instance wouldn't have already been in the work list is
@@ -759,12 +767,13 @@ void BfContext::HandleChangedTypeDef(BfTypeDef* typeDef, bool isAutoCompleteTemp
 {
 	BF_ASSERT(typeDef->mEmitParent == NULL);
 
-	if ((mCompiler->mResolvePassData == NULL) || (!typeDef->HasSource(mCompiler->mResolvePassData->mParser)))
+	if ((mCompiler->mResolvePassData == NULL) || (mCompiler->mResolvePassData->mParsers.IsEmpty()) ||
+		(!typeDef->HasSource(mCompiler->mResolvePassData->mParsers[0])))
 		return;
 
 	if (typeDef->mDefState != BfTypeDef::DefState_Defined)
 	{		
-		if (mCompiler->mResolvePassData->mSourceClassifier != NULL)
+		if (mCompiler->mResolvePassData->mIsClassifying)		
 		{							
 			auto _CheckSource = [&](BfTypeDef* checkTypeDef)
 			{
@@ -774,12 +783,11 @@ void BfContext::HandleChangedTypeDef(BfTypeDef* typeDef, bool isAutoCompleteTemp
 				if (typeDecl == NULL)
 					return;
 
-				if (typeDecl->GetSourceData() == mCompiler->mResolvePassData->mParser->mSourceData)
+				if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(typeDecl))
 				{
-					SetAndRestoreValue<bool> prevSkipTypeDeclaration(mCompiler->mResolvePassData->mSourceClassifier->mSkipTypeDeclarations, true);
-					auto classifier = mCompiler->mResolvePassData->mSourceClassifier;
-					classifier->mSkipMethodInternals = isAutoCompleteTempType;
-					classifier->Handle(typeDecl);
+					SetAndRestoreValue<bool> prevSkipTypeDeclaration(sourceClassifier->mSkipTypeDeclarations, true);					
+					sourceClassifier->mSkipMethodInternals = isAutoCompleteTempType;
+					sourceClassifier->Handle(typeDecl);
 				}
 			};
 

+ 2 - 0
IDEHelper/Compiler/BfContext.h

@@ -156,6 +156,7 @@ public:
 	BfFieldDef* mCurFieldDef;	
 	BfTypeDef* mCurTypeDef;
 	BfTypeDef* mForceActiveTypeDef;	
+	BfProject* mActiveProject;
 	ResolveKind mResolveKind;
 	BfAstNode* mCurVarInitializer;
 	int mArrayInitializerSize;
@@ -174,6 +175,7 @@ public:
 		mCurAttributeTypeRef = NULL;
 		mCurTypeDef = NULL;
 		mForceActiveTypeDef = NULL;
+		mActiveProject = NULL;
 		mCurVarInitializer = NULL;
 		mArrayInitializerSize = -1;
 		mResolveKind = ResolveKind_None;

+ 20 - 9
IDEHelper/Compiler/BfDefBuilder.cpp

@@ -153,8 +153,12 @@ void BfDefBuilder::Visit(BfIdentifierNode* identifier)
 //  already been handled, so we need to ignore that space while determining if we're "inside" this method or not during
 //  autocompletion
 bool BfDefBuilder::WantsNode(BfAstNode* wholeNode, BfAstNode* startNode, int addLen)
-{	
-	if ((mResolvePassData == NULL) || (mResolvePassData->mParser->mCursorIdx == -1))
+{		
+	if ((mResolvePassData == NULL) || (!mResolvePassData->mHasCursorIdx))
+		return true;
+
+	auto parser = wholeNode->GetParser();
+	if (parser->mCursorIdx == -1)
 		return true;
 
 	// We need to get all nodes when we get fixits because the cursor could be either before or after fields with
@@ -163,9 +167,9 @@ bool BfDefBuilder::WantsNode(BfAstNode* wholeNode, BfAstNode* startNode, int add
 		//return true;
 
 	addLen++;
-	if ((mResolvePassData->mParser->mCursorIdx >= wholeNode->GetSrcStart()) && (mResolvePassData->mParser->mCursorIdx < wholeNode->GetSrcEnd() + addLen))
+	if ((parser->mCursorIdx >= wholeNode->GetSrcStart()) && (parser->mCursorIdx < wholeNode->GetSrcEnd() + addLen))
 	{
-		if ((startNode == NULL) || (mResolvePassData->mParser->mCursorIdx >= startNode->GetSrcStart()))
+		if ((startNode == NULL) || (parser->mCursorIdx >= startNode->GetSrcStart()))
 			return true;
 	}
 	return false; 
@@ -1417,13 +1421,20 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 	{
 		isAutoCompleteTempType = (mResolvePassData->mAutoComplete != NULL);
 
-		int cursorIdx = mResolvePassData->mParser->mCursorIdx;		
-		if (typeDeclaration->Contains(cursorIdx, 1, 0))
+		if (mResolvePassData->mHasCursorIdx)
 		{
-			// Within bounds
+			auto parser = typeDeclaration->GetParser();
+			if (parser != NULL)
+			{
+				int cursorIdx = parser->mCursorIdx;
+				if (typeDeclaration->Contains(cursorIdx, 1, 0))
+				{
+					// Within bounds
+				}
+				else if (cursorIdx != -1)
+					return;
+			}
 		}
-		else if (cursorIdx != -1)
-			return;
 	}
 
 	int curLine = 0;

+ 10 - 6
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -4260,7 +4260,8 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI
 			
 			if ((resolvingFieldDef != NULL) && 
 				(mModule->mCompiler->mResolvePassData != NULL) && 
-				(mModule->mCompiler->mResolvePassData->mParser == resolvingFieldDef->mFieldDeclaration->GetParser()) &&
+				(!mModule->mCompiler->mResolvePassData->mParsers.IsEmpty()) &&
+				(mModule->mCompiler->mResolvePassData->mParsers[0] == resolvingFieldDef->mFieldDeclaration->GetParser()) &&
 				(GetAutoComplete() != NULL))
 			{
 				return mModule->GetDefaultTypedValue(mModule->mCurTypeInstance);
@@ -8805,7 +8806,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
 	auto autoComplete = GetAutoComplete();
 	if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo))
 	{
-		if ((!targetSrc->IsFromParser(mModule->mCompiler->mResolvePassData->mParser)) ||
+		if ((!targetSrc->IsFromParser(mModule->mCompiler->mResolvePassData->mParsers[0])) ||
 			((autoComplete->mMethodMatchInfo->mInvocationSrcIdx != -1) && (autoComplete->mMethodMatchInfo->mInvocationSrcIdx != targetSrc->GetSrcStart())))
 		{
 			autoComplete->mIsCapturingMethodMatchInfo = false;
@@ -9247,10 +9248,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
 		}
 
 		if (enumResult)
-		{
-			if (mModule->mCompiler->WantsClassifyNode(targetSrc))
+		{			
+			if (mModule->mCompiler->mResolvePassData != NULL)
 			{
-				mModule->mCompiler->mResolvePassData->mSourceClassifier->SetElementType(targetSrc, BfSourceElementType_Normal);
+				if (auto sourceClassifier = mModule->mCompiler->mResolvePassData->GetSourceClassifier(targetSrc))
+				{
+					sourceClassifier->SetElementType(targetSrc, BfSourceElementType_Normal);
+				}
 			}
 			return enumResult;
 		}
@@ -14444,7 +14448,7 @@ void BfExprEvaluator::CheckObjectCreateTypeRef(BfType* expectingType, BfAstNode*
 {
 	auto autoComplete = GetAutoComplete();	
 	if ((autoComplete != NULL) && (afterNode != NULL) && (autoComplete->mIsAutoComplete) &&
-		(afterNode->IsFromParser(mModule->mCompiler->mResolvePassData->mParser)) &&
+		(afterNode->IsFromParser(mModule->mCompiler->mResolvePassData->mParsers[0])) &&
 		(afterNode->GetParser()->mCursorIdx == afterNode->GetSrcEnd() + 1))
 	{
 		BfType* expectingType = mExpectingType;

+ 45 - 32
IDEHelper/Compiler/BfModule.cpp

@@ -2874,11 +2874,10 @@ bool BfModule::CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* me
 
 void BfModule::SetElementType(BfAstNode* astNode, BfSourceElementType elementType)
 {
-	if ((mCompiler->mResolvePassData != NULL) &&
-		(mCompiler->mResolvePassData->mSourceClassifier != NULL) &&
-		(astNode->IsFromParser(mCompiler->mResolvePassData->mParser)))
+	if (mCompiler->mResolvePassData != NULL)		
 	{
-		mCompiler->mResolvePassData->mSourceClassifier->SetElementType(astNode, elementType);
+		if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(astNode))
+			sourceClassifier->SetElementType(astNode, elementType);
 	}
 }
 
@@ -4441,10 +4440,13 @@ BfTypedValue BfModule::GetFieldInitializerValue(BfFieldInstance* fieldInstance,
 	}
 	else
 	{
-		if ((mCompiler->mIsResolveOnly) && (mCompiler->mResolvePassData->mSourceClassifier != NULL) && (initializer->IsFromParser(mCompiler->mResolvePassData->mParser)))
+		if (mCompiler->mIsResolveOnly)
 		{
-			mCompiler->mResolvePassData->mSourceClassifier->SetElementType(initializer, BfSourceElementType_Normal);
-			mCompiler->mResolvePassData->mSourceClassifier->VisitChildNoRef(initializer);
+			if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(initializer))
+			{
+				sourceClassifier->SetElementType(initializer, BfSourceElementType_Normal);
+				sourceClassifier->VisitChildNoRef(initializer);
+			}
 		}
 
 		if ((mCurTypeInstance->IsPayloadEnum()) && (fieldDef->IsEnumCaseEntry()))
@@ -11631,10 +11633,10 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 	if (!mCompiler->mHasRequiredTypes)
 		return;
 
-	if ((attributesDirective != NULL) && (mCompiler->mResolvePassData != NULL) && 
-		(attributesDirective->IsFromParser(mCompiler->mResolvePassData->mParser)) && (mCompiler->mResolvePassData->mSourceClassifier != NULL))
+	if ((attributesDirective != NULL) && (mCompiler->mResolvePassData != NULL))		
 	{
-		mCompiler->mResolvePassData->mSourceClassifier->VisitChild(attributesDirective);
+		if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(attributesDirective))
+			sourceClassifier->VisitChild(attributesDirective);
 	}
 
 	SetAndRestoreValue<bool> prevIsCapturingMethodMatchInfo;
@@ -11644,6 +11646,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 	BfTypeInstance* baseAttrTypeInst = mContext->mUnreifiedModule->ResolveTypeDef(mCompiler->mAttributeTypeDef)->ToTypeInstance();
 	BfAttributeTargets targetOverride = (BfAttributeTargets)0;
 
+	BfTypeDef* activeTypeDef = GetActiveTypeDef();
 	BfAutoComplete* autoComplete = NULL;
 	if (mCompiler->mResolvePassData != NULL)
 		autoComplete = mCompiler->mResolvePassData->mAutoComplete;
@@ -11674,6 +11677,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 
 		BfCustomAttribute customAttribute;
 		customAttribute.mAwaitingValidation = true;
+		customAttribute.mDeclaringType = activeTypeDef;
 		customAttribute.mRef = attributesDirective;
 
 		if (attributesDirective->mAttrOpenToken != NULL)
@@ -12109,7 +12113,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 		}
 
 		if (success)
-		{
+		{			
 			customAttributes->mAttributes.push_back(customAttribute);
 		}
 	}
@@ -13446,10 +13450,10 @@ BfModule* BfModule::GetOrCreateMethodModule(BfMethodInstance* methodInstance)
 		if (methodDecl != NULL)
 		{
 			auto attributesDirective = methodDecl->mAttributes;
-			if ((attributesDirective != NULL) && (mCompiler->mResolvePassData != NULL) &&
-				(attributesDirective->IsFromParser(mCompiler->mResolvePassData->mParser)) && (mCompiler->mResolvePassData->mSourceClassifier != NULL))
+			if ((attributesDirective != NULL) && (mCompiler->mResolvePassData != NULL))				
 			{
-				mCompiler->mResolvePassData->mSourceClassifier->VisitChild(attributesDirective);
+				if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(attributesDirective))
+					sourceClassifier->VisitChild(attributesDirective);
 			}
 		}
 	}
@@ -16239,7 +16243,7 @@ bool BfModule::IsInterestedInMethod(BfTypeInstance* typeInstance, BfMethodDef* m
 	if (methodDeclaration == NULL)
 		checkNode = methodDef->mBody;
 	
-	if ((mCompiler->mResolvePassData->mParser != NULL) && (typeDef->mTypeDeclaration->IsFromParser(mCompiler->mResolvePassData->mParser)))
+	if ((!mCompiler->mResolvePassData->mParsers.IsEmpty()) && (typeDef->mTypeDeclaration->IsFromParser(mCompiler->mResolvePassData->mParsers[0])))
 	{
 		if (mCompiler->mResolvePassData->mAutoComplete == NULL)
 			return true;		
@@ -16650,10 +16654,10 @@ void BfModule::CreateStaticCtor()
 					{
 						if (fieldDef->mInitializer != NULL)
 						{
-							if (mCompiler->mResolvePassData->mSourceClassifier != NULL)
+							if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(fieldDef->mInitializer))
 							{
-								mCompiler->mResolvePassData->mSourceClassifier->SetElementType(fieldDef->mInitializer, BfSourceElementType_Normal);
-								mCompiler->mResolvePassData->mSourceClassifier->VisitChild(fieldDef->mInitializer);
+								sourceClassifier->SetElementType(fieldDef->mInitializer, BfSourceElementType_Normal);
+								sourceClassifier->VisitChild(fieldDef->mInitializer);
 							}
 							BfType* wantType = NULL;
 							if ((!BfNodeIsA<BfVarTypeReference>(fieldDef->mTypeRef)) && (!BfNodeIsA<BfLetTypeReference>(fieldDef->mTypeRef)))
@@ -16835,10 +16839,13 @@ void BfModule::EmitDtorBody()
 
 				while (fieldDtor != NULL)
 				{
-					if (mCompiler->WantsClassifyNode(fieldDtor))
+					if (mCompiler->mResolvePassData != NULL)
 					{
-						mCompiler->mResolvePassData->mSourceClassifier->SetElementType(fieldDtor, BfSourceElementType_Normal);
-						mCompiler->mResolvePassData->mSourceClassifier->VisitChild(fieldDtor);
+						if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(fieldDtor))
+						{
+							sourceClassifier->SetElementType(fieldDtor, BfSourceElementType_Normal);
+							sourceClassifier->VisitChild(fieldDtor);
+						}
 					}
 
 					UpdateSrcPos(fieldDtor);										
@@ -16910,7 +16917,7 @@ void BfModule::EmitDtorBody()
 				for (auto fieldDef : tempTypeDef->mFields)
 				{
 					if ((fieldDef->mIsStatic == methodDef->mIsStatic) && (fieldDef->mFieldDeclaration != NULL) && 
-						(fieldDef->mFieldDeclaration->mFieldDtor != NULL) && (mCompiler->mResolvePassData->mSourceClassifier != NULL))
+						(fieldDef->mFieldDeclaration->mFieldDtor != NULL) && (mCompiler->mResolvePassData->mIsClassifying))
 					{
 						BfType* fieldType = NULL;
 
@@ -16943,8 +16950,11 @@ void BfModule::EmitDtorBody()
 
 						while (fieldDtor != NULL)
 						{
-							mCompiler->mResolvePassData->mSourceClassifier->SetElementType(fieldDtor, BfSourceElementType_Normal);
-							mCompiler->mResolvePassData->mSourceClassifier->VisitChild(fieldDtor);
+							if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(fieldDtor))
+							{
+								sourceClassifier->SetElementType(fieldDtor, BfSourceElementType_Normal);
+								sourceClassifier->VisitChild(fieldDtor);
+							}
 
 							UpdateSrcPos(fieldDtor);							
 							VisitEmbeddedStatement(fieldDtor->mBody);
@@ -17659,10 +17669,13 @@ void BfModule::EmitCtorBody(bool& skipBody)
 				{
 					for (auto fieldDef : tempTypeDef->mFields)
 					{
-						if ((!fieldDef->mIsStatic) && (fieldDef->mInitializer != NULL) && (mCompiler->mResolvePassData->mSourceClassifier != NULL))
+						if ((!fieldDef->mIsStatic) && (fieldDef->mInitializer != NULL) && (mCompiler->mResolvePassData->mIsClassifying))
 						{
-							mCompiler->mResolvePassData->mSourceClassifier->SetElementType(fieldDef->mInitializer, BfSourceElementType_Normal);
-							mCompiler->mResolvePassData->mSourceClassifier->VisitChild(fieldDef->mInitializer);
+							if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(fieldDef->mInitializer))
+							{
+								sourceClassifier->SetElementType(fieldDef->mInitializer, BfSourceElementType_Normal);
+								sourceClassifier->VisitChild(fieldDef->mInitializer);
+							}
 
 							BfType* wantType = NULL;
 							if ((!BfNodeIsA<BfVarTypeReference>(fieldDef->mTypeRef)) &&
@@ -19300,12 +19313,12 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
 		BF_ASSERT(!methodInstance->mIRFunction.IsFake() || (methodInstance->GetImportCallKind() != BfImportCallKind_None));
 	}
 
-	SetAndRestoreValue<BfSourceClassifier*> prevSourceClassifier;
+	SetAndRestoreValue<bool> prevIsClassifying;
 	if (((methodInstance->mMethodDef->mMethodType == BfMethodType_CtorCalcAppend) || (methodInstance->mIsForeignMethodDef) || (methodInstance->IsSpecializedGenericMethod())) && 
 		(mCompiler->mResolvePassData != NULL))
 	{
 		// Don't classify on the CtorCalcAppend, just on the actual Ctor
-		prevSourceClassifier.Init(mCompiler->mResolvePassData->mSourceClassifier, NULL);
+		prevIsClassifying.Init(mCompiler->mResolvePassData->mIsClassifying, false);
 	}
 
 	if (methodInstance->mHasBeenProcessed)
@@ -19573,10 +19586,10 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
 		
 	if ((mCurMethodState == NULL) && (!IsInSpecializedSection())) // Only do initial classify for the 'outer' method state, not any local methods or lambdas
 	{
-		if ((mCompiler->mIsResolveOnly) && (!mIsComptimeModule) && (methodDef->mBody != NULL) && (!mCurTypeInstance->IsBoxed()) &&
-			(methodDef->mBody->IsFromParser(mCompiler->mResolvePassData->mParser)) && (mCompiler->mResolvePassData->mSourceClassifier != NULL))
+		if ((mCompiler->mIsResolveOnly) && (!mIsComptimeModule) && (methodDef->mBody != NULL) && (!mCurTypeInstance->IsBoxed()))
 		{
-			mCompiler->mResolvePassData->mSourceClassifier->VisitChildNoRef(methodDef->mBody);
+			if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(methodDef->mBody))
+				sourceClassifier->VisitChildNoRef(methodDef->mBody);
 		}
 	}		
 

+ 3 - 2
IDEHelper/Compiler/BfModule.h

@@ -34,6 +34,7 @@ class BfResolvedType;
 class BfExprEvaluator;
 class CeEmitContext;
 class CeDbgState;
+enum BfCeTypeEmitSourceKind;
 
 enum BfPopulateType
 {	
@@ -1780,8 +1781,8 @@ public:
 	BfModuleOptions GetModuleOptions();
 	BfCheckedKind GetDefaultCheckedKind();
 	void FinishCEParseContext(BfAstNode* refNode, BfTypeInstance* typeInstance, BfCEParseContext* ceParseContext);
-	BfCEParseContext CEEmitParse(BfTypeInstance* typeInstance, const StringImpl& src);
-	void UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, const StringImpl& ctxString, BfAstNode* refNode);
+	BfCEParseContext CEEmitParse(BfTypeInstance* typeInstance, BfTypeDef* declaringType, const StringImpl& src, BfAstNode* refNode, BfCeTypeEmitSourceKind emitSourceKind);
+	void UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfTypeDef* declaringType, const StringImpl& ctxString, BfAstNode* refNode, BfCeTypeEmitSourceKind emitSourceKind);
 	void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfCustomAttributes* customAttributes, Dictionary<BfTypeInstance*, BfIRValue>& foundAttributes, bool underlyingTypeDeferred);
 	void CEMixin(BfAstNode* refNode, const StringImpl& src);
 	void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred);

+ 212 - 72
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -2023,7 +2023,7 @@ void BfModule::SetTypeOptions(BfTypeInstance* typeInstance)
 	typeInstance->mTypeOptionsIdx = GenerateTypeOptions(typeInstance->mCustomAttributes, typeInstance, true);
 }
 
-BfCEParseContext BfModule::CEEmitParse(BfTypeInstance* typeInstance, const StringImpl& src)
+BfCEParseContext BfModule::CEEmitParse(BfTypeInstance* typeInstance, BfTypeDef* declaringType, const StringImpl& src, BfAstNode* refNode, BfCeTypeEmitSourceKind emitSourceKind)
 {
 	BfCEParseContext ceParseContext;
 	ceParseContext.mFailIdx = mCompiler->mPassInstance->mFailedIdx;
@@ -2034,6 +2034,21 @@ BfCEParseContext BfModule::CEEmitParse(BfTypeInstance* typeInstance, const Strin
 	
 	BfParser* emitParser = NULL;
 
+	int64 emitSourceMapKey = ((int64)declaringType->mPartialIdx << 32) | refNode->mSrcStart;
+
+	if (typeInstance->mCeTypeInfo == NULL)
+		typeInstance->mCeTypeInfo = new BfCeTypeInfo();
+	auto ceTypeInfo = typeInstance->mCeTypeInfo;
+	if (ceTypeInfo->mNext != NULL)
+		ceTypeInfo = ceTypeInfo->mNext;	
+	BfCeTypeEmitSource* ceEmitSource = NULL;
+	ceTypeInfo->mEmitSourceMap.TryAdd(emitSourceMapKey, NULL, &ceEmitSource);
+	ceEmitSource->mKind = emitSourceKind;
+	
+	int emitSrcStart = 0;
+
+	BfEmitEmbedEntry* emitEmbedEntry = NULL;
+	
 	if (typeInstance->mTypeDef->mEmitParent == NULL)
 	{
 		BF_ASSERT(typeInstance->mTypeDef->mNextRevision == NULL);
@@ -2048,21 +2063,38 @@ BfCEParseContext BfModule::CEEmitParse(BfTypeInstance* typeInstance, const Strin
 		createdParser = true;		
 		emitParser = new BfParser(mSystem, typeInstance->mTypeDef->mProject);
 		emitParser->mIsEmitted = true;
-		emitParser->mFileName = typeInstance->mTypeDef->mName->ToString();
-
+		
 		BfLogSys(mSystem, "Emit typeDef for type %p created %p parser %p typeDecl %p\n", typeInstance, emitTypeDef, emitParser, emitTypeDef->mTypeDeclaration);
 
-		if (mCompiler->mIsResolveOnly)
-			emitParser->mFileName += "$EmitR$";
-		else
-			emitParser->mFileName += "$Emit$";
+		String typeName;		
+		typeName += typeInstance->mTypeDef->mProject->mName;
+		typeName += ":";
+
+		typeName += TypeToString(typeInstance, BfTypeNameFlags_None);
+		if ((mCompiler->mResolvePassData != NULL) && (!mCompiler->mResolvePassData->mEmitEmbedEntries.IsEmpty()))
+			mCompiler->mResolvePassData->mEmitEmbedEntries.TryGetValue(typeName, &emitEmbedEntry);
+ 		
+		emitParser->mFileName = "$Emit$";
+		emitParser->mFileName += typeName;
 
-		emitParser->mFileName += StrFormat("%d", typeInstance->mTypeId);
-		emitParser->mFileName += StrFormat(".bf|%d", typeInstance->mRevision);
 		emitTypeDef->mSource = emitParser;
 		emitParser->mRefCount++;
 		emitParser->SetSource(src.c_str(), src.mLength);
 
+		if (emitEmbedEntry != NULL)
+		{
+			emitEmbedEntry->mRevision = typeInstance->mRevision;
+			emitEmbedEntry->mParser = emitParser;
+			emitEmbedEntry->mParser->mSourceClassifier = new BfSourceClassifier(emitEmbedEntry->mParser, NULL);			
+			mCompiler->mPassInstance->mFilterErrorsTo.Add(emitEmbedEntry->mParser->mParserData);
+
+			if (emitEmbedEntry->mCursorIdx != -1)
+			{
+				emitParser->SetCursorIdx(emitEmbedEntry->mCursorIdx);
+				emitParser->mParserFlags = (BfParserFlag)(emitParser->mParserFlags | ParserFlag_Autocomplete | ParserFlag_Classifying);
+			}
+		}
+
 		// If we emit only from method attributes then we will already have method instances created
 		auto _FixMethod = [&](BfMethodInstance* methodInstance)
 		{
@@ -2082,19 +2114,57 @@ BfCEParseContext BfModule::CEEmitParse(BfTypeInstance* typeInstance, const Strin
 		};
 	}
 	else
-	{		
+	{
 		emitParser = typeInstance->mTypeDef->mSource->ToParser();
 
-		int idx = emitParser->AllocChars(src.mLength + 1);
-		memcpy((uint8*)emitParser->mSrc + idx, src.c_str(), src.mLength + 1);
+		if ((mCompiler->mResolvePassData != NULL) && (!mCompiler->mResolvePassData->mEmitEmbedEntries.IsEmpty()))
+		{			
+			int dollarPos = (int)emitParser->mFileName.LastIndexOf('$');
+			if (dollarPos != -1)
+				mCompiler->mResolvePassData->mEmitEmbedEntries.TryGetValue(emitParser->mFileName.Substring(dollarPos + 1), &emitEmbedEntry);
+		}
+
+		int idx = emitParser->AllocChars(2 + src.mLength + 1);
+		emitSrcStart = idx + 2;
+
+		memcpy((uint8*)emitParser->mSrc + idx, "\n\n", 2);
+		memcpy((uint8*)emitParser->mSrc + idx + 2, src.c_str(), src.mLength + 1);
 		emitParser->mSrcIdx = idx;
-		emitParser->mSrcLength = idx + src.mLength;
+		emitParser->mSrcLength = idx + src.mLength + 2;
 		emitParser->mParserData->mSrcLength = emitParser->mSrcLength;
+		emitParser->mOrigSrcLength = emitParser->mSrcLength;
+	}
+
+	if (ceEmitSource->mSrcStart == -1)
+	{
+		ceEmitSource->mSrcStart = emitSrcStart;
+		ceEmitSource->mSrcEnd = emitParser->mSrcLength;
+	}
+	else
+	{
+		ceEmitSource->mSrcStart = BF_MIN(ceEmitSource->mSrcStart, emitSrcStart);
+		ceEmitSource->mSrcEnd = BF_MAX(ceEmitSource->mSrcEnd, emitParser->mSrcLength);
 	}
 
 	emitParser->Parse(mCompiler->mPassInstance);
 	emitParser->FinishSideNodes();
 
+	if (emitEmbedEntry != NULL)
+	{
+		int prevStart = emitEmbedEntry->mCharData.mSize;
+		emitEmbedEntry->mCharData.GrowUninitialized(emitParser->mSrcLength - emitEmbedEntry->mCharData.mSize);
+		auto charDataPtr = emitEmbedEntry->mCharData.mVals;
+		for (int i = prevStart; i < emitParser->mSrcLength; i++)
+		{
+			charDataPtr[i].mChar = emitParser->mSrc[i];
+			charDataPtr[i].mDisplayPassId = 0;
+			charDataPtr[i].mDisplayTypeId = 0;
+			charDataPtr[i].mDisplayFlags = 0;
+		}
+
+		emitEmbedEntry->mParser->mSourceClassifier->mCharData = emitEmbedEntry->mCharData.mVals;		
+	}
+
 	if (createdParser)
 	{
 		AutoCrit crit(mSystem->mDataLock);
@@ -2117,7 +2187,7 @@ void BfModule::FinishCEParseContext(BfAstNode* refNode, BfTypeInstance* typeInst
 	}
 }
 
-void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, const StringImpl& ctxString, BfAstNode* refNode)
+void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfTypeDef* declaringType, const StringImpl& ctxString, BfAstNode* refNode, BfCeTypeEmitSourceKind emitSourceKind)
 {
 	for (int ifaceTypeId : ceEmitContext->mInterfaces)
 		typeInstance->mCeTypeInfo->mPendingInterfaces.Add(ifaceTypeId);
@@ -2127,16 +2197,16 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn
 		
 	String src;
 		
-	if (typeInstance->mTypeDef->mEmitParent != NULL)
-		src += "\n\n";
+// 	if (typeInstance->mTypeDef->mEmitParent != NULL)
+// 		src += "\n\n";
 
-	src += "// Code emission in ";
-	src += ctxString;
-	src += "\n\n";
+// 	src += "// Code emission in ";
+// 	src += ctxString;
+// 	src += "\n\n";
 	src += ceEmitContext->mEmitData;	
 	ceEmitContext->mEmitData.Clear();
 
-	BfCEParseContext ceParseContext = CEEmitParse(typeInstance, src);	
+	BfCEParseContext ceParseContext = CEEmitParse(typeInstance, declaringType, src, refNode, emitSourceKind);	
 	auto emitParser = typeInstance->mTypeDef->mSource->ToParser();
 				
 	auto typeDeclaration = emitParser->mAlloc->Alloc<BfTypeDeclaration>();
@@ -2167,6 +2237,13 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn
 
 	FinishCEParseContext(refNode, typeInstance, &ceParseContext);
 
+	if (emitParser->mSourceClassifier != NULL)
+	{
+		emitParser->mSourceClassifier->VisitChild(emitParser->mRootNode);
+		emitParser->mSourceClassifier->VisitChild(emitParser->mSidechannelRootNode);
+		emitParser->mSourceClassifier->VisitChild(emitParser->mErrorRootNode);
+	}
+
 	if (typeInstance->mTypeDef->mEmitParent != NULL)
 	{
 		// Remove generated fields like the 'underlying type' enum field
@@ -2347,7 +2424,8 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance*
 				ctxStr += TypeToString(typeInstance);
 				ctxStr += " ";
 				ctxStr += customAttribute.mRef->LocationToString();
-				UpdateCEEmit(ceEmitContext, typeInstance, ctxStr, customAttribute.mRef);
+
+				UpdateCEEmit(ceEmitContext, typeInstance, customAttribute.mDeclaringType, ctxStr, customAttribute.mRef, BfCeTypeEmitSourceKind_Type);
 			}
 		}
 
@@ -2361,11 +2439,11 @@ void BfModule::CEMixin(BfAstNode* refNode, const StringImpl& code)
 	//auto emitParser = activeTypeDef->mEmitParser;
 			
 	String src;
-	if (mCurTypeInstance->mTypeDef->mEmitParent != NULL)
-		src += "\n\n";
-	src += "// Code emission in ";	
-	src += MethodToString(mCurMethodInstance);	
-	src += "\n";
+// 	if (mCurTypeInstance->mTypeDef->mEmitParent != NULL)
+// 		src += "\n\n";
+// 	src += "// Code emission in ";	
+// 	src += MethodToString(mCurMethodInstance);	
+// 	src += "\n";
 	src += code;
 
 	BfReducer bfReducer;	
@@ -2380,7 +2458,7 @@ void BfModule::CEMixin(BfAstNode* refNode, const StringImpl& code)
 	bool wantsDIData = (mBfIRBuilder->DbgHasInfo()) && (mHasFullDebugInfo);
 	mBfIRBuilder->SaveDebugLocation();
 
-	BfCEParseContext ceParseContext = CEEmitParse(mCurTypeInstance, src);
+	BfCEParseContext ceParseContext = CEEmitParse(mCurTypeInstance, activeTypeDef, src, refNode, BfCeTypeEmitSourceKind_Method);
 	auto emitParser = mCurTypeInstance->mTypeDef->mSource->ToParser();
 	bfReducer.mSource = emitParser;
 	bfReducer.mAlloc = emitParser->mAlloc;
@@ -2503,6 +2581,11 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
 		if (methodDeclaration->mAttributes == NULL)
 			continue;
 
+		BfTypeState typeState;
+		typeState.mPrevState = mContext->mCurTypeState;
+		typeState.mForceActiveTypeDef = methodDef->mDeclaringType;
+		SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
+
 		bool wantsAttributes = false;		
 		BfAttributeDirective* checkAttributes = methodDeclaration->mAttributes;
 		while (checkAttributes != NULL)
@@ -2607,7 +2690,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
 				ctxStr += MethodToString(methodInstance);
 				ctxStr += " ";
 				ctxStr += methodInstance->mMethodDef->GetRefNode()->LocationToString();
-				UpdateCEEmit(ceEmitContext, typeInstance, ctxStr, methodInstance->mMethodDef->GetRefNode());
+				UpdateCEEmit(ceEmitContext, typeInstance, methodDef->mDeclaringType, ctxStr, methodInstance->mMethodDef->GetRefNode(), BfCeTypeEmitSourceKind_Type);
 			}
 		}
 
@@ -2751,13 +2834,13 @@ void BfModule::DoCEEmit(BfMethodInstance* methodInstance)
 		if ((!ceEmitContext.mEmitData.IsEmpty()) || (!ceEmitContext.mExitEmitData.IsEmpty()))
 		{
 			String src;				
-			src += "// Code emission in comptime ApplyToMethod of ";
-			src += TypeToString(attrType);
-			src += " to ";
-			src += MethodToString(methodInstance);
-			src += " ";
-			src += customAttribute.mRef->LocationToString();
-			src += "\n";
+// 			src += "// Code emission in comptime ApplyToMethod of ";
+// 			src += TypeToString(attrType);
+// 			src += " to ";
+// 			src += MethodToString(methodInstance);
+// 			src += " ";
+// 			src += customAttribute.mRef->LocationToString();
+// 			src += "\n";
 				
 			//auto emitTypeDef = typeInstance->mCeTypeInfo->mNext->mTypeDef;
 			//auto emitParser = emitTypeDef->mSource->ToParser();
@@ -2771,16 +2854,29 @@ void BfModule::DoCEEmit(BfMethodInstance* methodInstance)
 			bfReducer.mCurTypeDecl = activeTypeDef->mTypeDeclaration;
 			bfReducer.mCurMethodDecl = BfNodeDynCast<BfMethodDeclaration>(methodInstance->mMethodDef->mMethodDeclaration);
 
+			BfAstNode* bodyNode = NULL;			
+			if (auto methodDecl = BfNodeDynCast<BfMethodDeclaration>(methodInstance->mMethodDef->mMethodDeclaration))
+				bodyNode = methodDecl->mBody;
+
 			if (!ceEmitContext.mEmitData.IsEmpty())
 			{
-				SetAndRestoreValue<BfAstNode*> prevCustomAttribute(mCurMethodState->mEmitRefNode, customAttribute.mRef);
-
+				SetAndRestoreValue<BfAstNode*> prevCustomAttribute(mCurMethodState->mEmitRefNode, customAttribute.mRef);				
 				String entrySrc = src;
-				if (mCurTypeInstance->mTypeDef->mEmitParent != NULL)
-					entrySrc += "\n\n";
+// 				if (mCurTypeInstance->mTypeDef->mEmitParent != NULL)
+// 					entrySrc += "\n\n";
 				entrySrc += src;
 				entrySrc += ceEmitContext.mEmitData;
-				BfCEParseContext ceParseContext = CEEmitParse(typeInstance, entrySrc);
+
+				BfAstNode* refNode = customAttribute.mRef;
+				if (bodyNode != NULL)
+				{
+					refNode = bodyNode;
+					if (auto blockNode = BfNodeDynCast<BfBlock>(bodyNode))
+						if (blockNode->mOpenBrace != NULL)
+							refNode = blockNode->mOpenBrace;
+				}
+
+				BfCEParseContext ceParseContext = CEEmitParse(typeInstance, methodInstance->mMethodDef->mDeclaringType, entrySrc, refNode, BfCeTypeEmitSourceKind_Type);
 				auto emitParser = mCurTypeInstance->mTypeDef->mSource->ToParser();
 				bfReducer.mSource = emitParser;
 				bfReducer.mAlloc = emitParser->mAlloc;
@@ -2796,7 +2892,18 @@ void BfModule::DoCEEmit(BfMethodInstance* methodInstance)
 					exitSrc += "\n\n";
 				exitSrc += src;
 				exitSrc += ceEmitContext.mExitEmitData;
-				BfCEParseContext ceParseContext = CEEmitParse(typeInstance, exitSrc);
+
+				BfAstNode* refNode = customAttribute.mRef;
+				if (bodyNode != NULL)
+				{
+					refNode = bodyNode;
+					if (auto blockNode = BfNodeDynCast<BfBlock>(bodyNode))
+						if (blockNode->mCloseBrace != NULL)
+							refNode = blockNode->mCloseBrace;
+				}
+
+				BfCEParseContext ceParseContext = CEEmitParse(typeInstance, methodInstance->mMethodDef->mDeclaringType, exitSrc, refNode, BfCeTypeEmitSourceKind_Type);
+
 				auto emitParser = mCurTypeInstance->mTypeDef->mSource->ToParser();
 				bfReducer.mSource = emitParser;
 				bfReducer.mAlloc = emitParser->mAlloc;
@@ -4540,7 +4647,14 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 				if (typeInstance->mCeTypeInfo->mNext != NULL)
 				{
 					auto ceInfo = typeInstance->mCeTypeInfo->mNext;
+
 					HashContext hashCtx;
+					hashCtx.Mixin(ceInfo->mEmitSourceMap.mCount);
+					for (auto& kv : ceInfo->mEmitSourceMap)
+					{
+						hashCtx.Mixin(kv.mKey);
+						hashCtx.Mixin(kv.mValue);
+					}
 					hashCtx.Mixin(ceInfo->mOnCompileMap.mCount);
 					for (auto& kv : ceInfo->mOnCompileMap)
 					{
@@ -4559,15 +4673,26 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 					if (!typeInstance->mCeTypeInfo->mNext->mFailed)
 					{
 						if ((typeInstance->mCeTypeInfo->mHash != typeInstance->mCeTypeInfo->mNext->mHash) && (!typeInstance->mCeTypeInfo->mHash.IsZero()))
-							mContext->RebuildDependentTypes_MidCompile(typeInstance, "comptime hash changed");												
+							mContext->RebuildDependentTypes_MidCompile(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;
 				}
+				else
+				{
+					// Removed emissions
+					if (!typeInstance->mCeTypeInfo->mHash.IsZero())
+						mContext->RebuildDependentTypes_MidCompile(typeInstance, "comptime hash changed");
+					typeInstance->mCeTypeInfo->mEmitSourceMap.Clear();
+					typeInstance->mCeTypeInfo->mOnCompileMap.Clear();
+					typeInstance->mCeTypeInfo->mTypeIFaceMap.Clear();
+					typeInstance->mCeTypeInfo->mHash = Val128();
+				}
 			}
 
 			if ((typeInstance->mCeTypeInfo != NULL) && (!typeInstance->mCeTypeInfo->mPendingInterfaces.IsEmpty()))
@@ -5312,16 +5437,19 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 		if ((typeDeclaration != NULL) && (typeDeclaration->mNameNode != NULL))
 		{
 			auto typeRefSource = typeDeclaration->mNameNode->GetParserData();
-			if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mSourceClassifier != NULL) && (typeRefSource != NULL) && (typeRefSource == mCompiler->mResolvePassData->mParser->mSourceData))
+			if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mIsClassifying) && (typeRefSource != NULL))
 			{
-				BfSourceElementType elemType = BfSourceElementType_Type;
-				if (typeInstance->IsInterface())
-					elemType = BfSourceElementType_Interface;
-				else if (typeInstance->IsObject())
-					elemType = BfSourceElementType_RefType;
-				else if (typeInstance->IsStruct() || (typeInstance->IsTypedPrimitive() && !typeInstance->IsEnum()))
-					elemType = BfSourceElementType_Struct;
-				mCompiler->mResolvePassData->mSourceClassifier->SetElementType(typeDeclaration->mNameNode, elemType);
+				if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(typeDeclaration->mNameNode))
+				{
+					BfSourceElementType elemType = BfSourceElementType_Type;
+					if (typeInstance->IsInterface())
+						elemType = BfSourceElementType_Interface;
+					else if (typeInstance->IsObject())
+						elemType = BfSourceElementType_RefType;
+					else if (typeInstance->IsStruct() || (typeInstance->IsTypedPrimitive() && !typeInstance->IsEnum()))
+						elemType = BfSourceElementType_Struct;
+					sourceClassifier->SetElementType(typeDeclaration->mNameNode, elemType);
+				}
 			}
 		}
 	};
@@ -8775,11 +8903,17 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 		else
 			typeRefSource = typeRef->GetSourceData();
 
-		bool wantsFileNamespaceInfo = (((mCompiler->mResolvePassData->mSourceClassifier != NULL) || (isGetDefinition) || (mCompiler->mResolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Namespace)) &&
-			(typeRefSource != NULL) && (mCompiler->mResolvePassData->mParser != NULL) &&
-			(typeRefSource == mCompiler->mResolvePassData->mParser->mSourceData));
+		BfSourceClassifier* sourceClassifier = NULL;
+		if ((mCompiler->mResolvePassData->mIsClassifying) && (typeRefSource != NULL))
+		{
+			auto parser = typeRefSource->ToParser();
+			if (parser != NULL)
+				sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(parser);
+		}
+
+		bool wantsFileNamespaceInfo = ((sourceClassifier != NULL) || (isGetDefinition) || (mCompiler->mResolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Namespace));
 
-		bool wantsAllNamespaceInfo = (mCompiler->mResolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Namespace) && (mCompiler->mResolvePassData->mParser == NULL);
+		bool wantsAllNamespaceInfo = (mCompiler->mResolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Namespace) && (mCompiler->mResolvePassData->mParsers.IsEmpty());
 
 		if (wantsFileNamespaceInfo || wantsAllNamespaceInfo)
 		{
@@ -8841,14 +8975,14 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 
 			while (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(checkTypeRef))
 			{
-				if ((mCompiler->mResolvePassData->mSourceClassifier != NULL) && (checkTypeRef == headTypeRef) && (elemType != BfSourceElementType_Type))
-					mCompiler->mResolvePassData->mSourceClassifier->SetElementType(qualifiedTypeRef->mRight, elemType);
+				if ((sourceClassifier != NULL) && (checkTypeRef == headTypeRef) && (elemType != BfSourceElementType_Type))
+					sourceClassifier->SetElementType(qualifiedTypeRef->mRight, elemType);
 
 				StringView leftString = qualifiedTypeRef->mLeft->ToStringView();
 				BfSizedAtomComposite leftComposite;
 				bool isValid = mSystem->ParseAtomComposite(leftString, leftComposite);
-				if (mCompiler->mResolvePassData->mSourceClassifier != NULL)
-					mCompiler->mResolvePassData->mSourceClassifier->SetHighestElementType(qualifiedTypeRef->mRight, isNamespace ? BfSourceElementType_Namespace : BfSourceElementType_Type);
+				if (sourceClassifier != NULL)
+					sourceClassifier->SetHighestElementType(qualifiedTypeRef->mRight, isNamespace ? BfSourceElementType_Namespace : BfSourceElementType_Type);
 				if (resolvedTypeInstance == NULL)
 				{
 					if ((isValid) && (mCompiler->mSystem->ContainsNamespace(leftComposite, mCurTypeInstance->mTypeDef->mProject)))
@@ -8874,16 +9008,16 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 				auto checkNameNode = namedTypeRef->mNameNode;
 				bool setType = false;
 
-				if ((mCompiler->mResolvePassData->mSourceClassifier != NULL) && (checkTypeRef == headTypeRef) && (elemType != BfSourceElementType_Type))
+				if ((sourceClassifier != NULL) && (checkTypeRef == headTypeRef) && (elemType != BfSourceElementType_Type))
 				{					
 					if (auto qualifiedNameNode = BfNodeDynCast<BfQualifiedNameNode>(checkNameNode))
 					{
-						mCompiler->mResolvePassData->mSourceClassifier->SetElementType(qualifiedNameNode->mRight, elemType);
+						sourceClassifier->SetElementType(qualifiedNameNode->mRight, elemType);
 					}
 					else
 					{
 						setType = true;
-						mCompiler->mResolvePassData->mSourceClassifier->SetElementType(checkNameNode, elemType);
+						sourceClassifier->SetElementType(checkNameNode, elemType);
 					}
 				}
 
@@ -8892,8 +9026,8 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 					StringView leftString =  qualifiedNameNode->mLeft->ToStringView();
 					BfSizedAtomComposite leftComposite;
 					bool isValid = mSystem->ParseAtomComposite(leftString, leftComposite);
-					if (mCompiler->mResolvePassData->mSourceClassifier != NULL)
-						mCompiler->mResolvePassData->mSourceClassifier->SetHighestElementType(qualifiedNameNode->mRight, isNamespace ? BfSourceElementType_Namespace : BfSourceElementType_Type);
+					if (sourceClassifier != NULL)
+						sourceClassifier->SetHighestElementType(qualifiedNameNode->mRight, isNamespace ? BfSourceElementType_Namespace : BfSourceElementType_Type);
 					if (resolvedTypeInstance == NULL)
 					{
 						if ((isValid) && (mCompiler->mSystem->ContainsNamespace(leftComposite, mCurTypeInstance->mTypeDef->mProject)))
@@ -8913,9 +9047,9 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 					}
 					checkNameNode = qualifiedNameNode->mLeft;
 				}
-				if ((mCompiler->mResolvePassData->mSourceClassifier != NULL) && 
+				if ((sourceClassifier != NULL) &&
 					((!setType) || (checkNameNode != namedTypeRef->mNameNode)))
-					mCompiler->mResolvePassData->mSourceClassifier->SetHighestElementType(checkNameNode, isNamespace ? BfSourceElementType_Namespace : BfSourceElementType_Type);
+					sourceClassifier->SetHighestElementType(checkNameNode, isNamespace ? BfSourceElementType_Namespace : BfSourceElementType_Type);
 			}
 		}
 
@@ -8964,6 +9098,7 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 								else
 									break;
 							}
+
 							if ((baseNode != NULL) && (autoComplete->IsAutocompleteNode(baseNode)))
 							{
 								// We didn't have this mDefType check before - why? We always want to catch the FIRST definition, 
@@ -9348,8 +9483,10 @@ BfTypeDef* BfModule::FindTypeDef(const BfAtomComposite& findName, int numGeneric
 	if ((typeInstance == NULL) && (useTypeDef == NULL))
 	{		
 		BfProject* project = NULL;
-		if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mParser != NULL))
-			project = mCompiler->mResolvePassData->mParser->mProject;
+		if ((mContext->mCurTypeState != NULL) && (mContext->mCurTypeState->mActiveProject != NULL))
+			project = mContext->mCurTypeState->mActiveProject;
+		else if ((mCompiler->mResolvePassData != NULL) && (!mCompiler->mResolvePassData->mParsers.IsEmpty()))
+			project = mCompiler->mResolvePassData->mParsers[0]->mProject;
 
 		BP_ZONE("System.FindTypeDef_2");				
 		Array<BfAtomComposite> namespaceSearch;
@@ -9535,7 +9672,7 @@ void BfModule::CheckTypeRefFixit(BfAstNode* typeRef, const char* appendName)
 		std::set<String> fixitNamespaces;
 
 		//TODO: Do proper value for numGenericArgs		
-		mSystem->FindFixitNamespaces(typeName, -1, mCompiler->mResolvePassData->mParser->mProject, fixitNamespaces);
+		mSystem->FindFixitNamespaces(typeName, -1, mCompiler->mResolvePassData->mParsers[0]->mProject, fixitNamespaces);
 
 		int insertLoc = 0;
 
@@ -9810,8 +9947,11 @@ BfTypedValue BfModule::TryLookupGenericConstVaue(BfIdentifierNode* identifierNod
 		if (genericParamResult != NULL)
 		{			
 			auto typeRefSource = identifierNode->GetSourceData();
-			if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mSourceClassifier != NULL) && (typeRefSource != NULL) && (typeRefSource == mCompiler->mResolvePassData->mParser->mSourceData))
-				mCompiler->mResolvePassData->mSourceClassifier->SetElementType(identifierNode, BfSourceElementType_GenericParam);
+			if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mIsClassifying) && (typeRefSource != NULL))
+			{
+				if (auto sourceClassifier = mCompiler->mResolvePassData->GetSourceClassifier(identifierNode))
+					sourceClassifier->SetElementType(identifierNode, BfSourceElementType_GenericParam);
+			}
 
 			if (genericParamResult->IsConstExprValue())
 			{

+ 58 - 3
IDEHelper/Compiler/BfParser.cpp

@@ -345,6 +345,7 @@ BfParser::BfParser(BfSystem* bfSystem, BfProject* bfProject) : BfSource(bfSystem
 
 	gParserCount++;	
 
+	mEmbedKind = BfSourceEmbedKind_None;
 	mUsingCache = false;
 	mParserData = NULL;
 	mAwaitingDelete = false;
@@ -354,7 +355,7 @@ BfParser::BfParser(BfSystem* bfSystem, BfProject* bfProject) : BfSource(bfSystem
 	mJumpTable = NULL;
 	mProject = bfProject;
 	mPassInstance = NULL;
-	mPassInstance = NULL;
+	mSourceClassifier = NULL;
 	mPrevRevision = NULL;
 	mNextRevision = NULL;
 	mOrigSrcLength = 0;
@@ -375,7 +376,7 @@ BfParser::BfParser(BfSystem* bfSystem, BfProject* bfProject) : BfSource(bfSystem
 	mCompatMode = false;
 	mQuickCompatMode = false;
 	mLiteral.mWarnType = 0;
-	mDataId = -1;
+	mDataId = -1;	
 
 	mTriviaStart = 0;
 	mParsingFailed = false;
@@ -3820,6 +3821,11 @@ BF_EXPORT void BF_CALLTYPE BfParser_SetIsClassifying(BfParser* bfParser)
 	bfParser->mParserFlags = (BfParserFlag)(bfParser->mParserFlags | ParserFlag_Classifying);
 }
 
+BF_EXPORT void BF_CALLTYPE BfParser_SetEmbedKind(BfParser* bfParser, BfSourceEmbedKind embedKind)
+{
+	bfParser->mEmbedKind = embedKind;
+}
+
 BF_EXPORT void BF_CALLTYPE BfParser_SetAutocomplete(BfParser* bfParser, int cursorIdx)
 {
 	BF_ASSERT(bfParser->mParserData->mRefCount == -1);
@@ -3972,7 +3978,8 @@ BF_EXPORT BfResolvePassData* BF_CALLTYPE BfParser_CreateResolvePassData(BfParser
 {
 	auto bfResolvePassData = new BfResolvePassData();
 	bfResolvePassData->mResolveType = resolveType;
-	bfResolvePassData->mParser = bfParser;
+	if (bfParser != NULL)
+		bfResolvePassData->mParsers.Add(bfParser);
 	if ((bfParser != NULL) && ((bfParser->mParserFlags & ParserFlag_Autocomplete) != 0))
 		bfResolvePassData->mAutoComplete = new BfAutoComplete(resolveType, doFuzzyAutoComplete);
 	return bfResolvePassData;
@@ -3980,6 +3987,9 @@ BF_EXPORT BfResolvePassData* BF_CALLTYPE BfParser_CreateResolvePassData(BfParser
 
 BF_EXPORT bool BF_CALLTYPE BfParser_BuildDefs(BfParser* bfParser, BfPassInstance* bfPassInstance, BfResolvePassData* resolvePassData, bool fullRefresh)
 {	
+	if (bfParser->mCursorIdx != -1)
+		resolvePassData->mHasCursorIdx = true;
+
 	BP_ZONE("BfParser_BuildDefs");
 	int startFailIdx = bfPassInstance->mFailedIdx;
 	BfDefBuilder defBuilder(bfParser->mSystem);
@@ -4007,6 +4017,51 @@ BF_EXPORT void BF_CALLTYPE BfParser_ClassifySource(BfParser* bfParser, BfSourceC
 	bfSourceClassifier.Visit(bfParser->mSidechannelRootNode);	
 }
 
+BF_EXPORT void BF_CALLTYPE BfParser_CreateClassifier(BfParser* bfParser, BfPassInstance* bfPassInstance, BfResolvePassData* resolvePassData, BfSourceClassifier::CharData* charData)
+{
+	resolvePassData->mIsClassifying = true;
+	bfParser->mSourceClassifier = new BfSourceClassifier(bfParser, charData);	
+	bfParser->mSourceClassifier->mClassifierPassId = bfPassInstance->mClassifierPassId;
+
+	if ((resolvePassData->mParsers.IsEmpty()) || (bfParser != resolvePassData->mParsers[0]))
+		resolvePassData->mParsers.Add(bfParser);
+
+	bool doClassifyPass = (charData != NULL) && (resolvePassData->mResolveType <= BfResolveType_Autocomplete_HighPri);
+	bfParser->mSourceClassifier->mEnabled = doClassifyPass;
+
+	bfParser->mSourceClassifier->mSkipMethodInternals = true;
+	bfParser->mSourceClassifier->mSkipTypeDeclarations = true;
+	if (charData != NULL)
+	{		
+		if ((doClassifyPass) && (bfParser->mRootNode != NULL))
+			bfParser->mSourceClassifier->Visit(bfParser->mRootNode);
+	}
+	bfParser->mSourceClassifier->mSkipTypeDeclarations = false;
+	bfParser->mSourceClassifier->mSkipMethodInternals = false;
+}
+
+BF_EXPORT void BF_CALLTYPE BfParser_FinishClassifier(BfParser* bfParser, BfResolvePassData* resolvePassData)
+{
+	if (bfParser->mSourceClassifier == NULL)
+		return;
+
+	bool doClassifyPass = (bfParser->mSourceClassifier->mCharData != NULL) && (resolvePassData->mResolveType <= BfResolveType_Autocomplete_HighPri);
+
+	if (doClassifyPass)
+	{
+		bfParser->mSourceClassifier->mIsSideChannel = false;
+		if (bfParser->mErrorRootNode != NULL)
+			bfParser->mSourceClassifier->Visit(bfParser->mErrorRootNode);
+
+		bfParser->mSourceClassifier->mIsSideChannel = true;
+		if (bfParser->mSidechannelRootNode != NULL)
+			bfParser->mSourceClassifier->Visit(bfParser->mSidechannelRootNode);
+	}
+
+	delete bfParser->mSourceClassifier;
+	bfParser->mSourceClassifier = NULL;
+}
+
 BF_EXPORT void BF_CALLTYPE BfParser_GenerateAutoCompletionFrom(BfParser* bfParser, int srcPosition)
 {
 	BP_ZONE("BfParser_GenerateAutoCompletionFrom");

+ 11 - 1
IDEHelper/Compiler/BfParser.h

@@ -14,6 +14,7 @@ NS_BF_BEGIN
 
 class BfPassInstance;
 class BfProject;
+class BfSourceClassifier;
 
 enum BfSyntaxToken
 {
@@ -136,13 +137,20 @@ public:
 	void ReportMemory(MemReporter* memReporter);
 };
 
-enum BfDefineState
+enum BfDefineState : int8
 {
 	BfDefineState_FromProject,
 	BfDefineState_ManualSet,
 	BfDefineState_ManualUnset
 };
 
+enum BfSourceEmbedKind : int8
+{
+	BfSourceEmbedKind_None,
+	BfSourceEmbedKind_Type,
+	BfSourceEmbedKind_Method
+};
+
 class BfParser : public BfSource
 {
 public:		
@@ -150,7 +158,9 @@ public:
 	bool mUsingCache;
 
 	BfPassInstance* mPassInstance;
+	BfSourceClassifier* mSourceClassifier;
 	String mFileName;	
+	BfSourceEmbedKind mEmbedKind;
 	bool mAwaitingDelete;	
 	
 	bool mCompatMode; // Does C++ compatible parsing

+ 55 - 2
IDEHelper/Compiler/BfReducer.cpp

@@ -6781,7 +6781,8 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept
 // 	if (depth == 0)
 // 		prevTypeMemberNodeStart.Set();
 
-	AssertCurrentNode(node);
+	if (mCurTypeDecl != NULL)
+		AssertCurrentNode(node);
 
 	BfTokenNode* refToken = NULL;
 
@@ -8239,6 +8240,58 @@ BfAstNode* BfReducer::HandleTopLevel(BfBlock* node)
 	bool hadPrevFail = false;
 
 	bool isDone = !mVisitorPos.MoveNext();
+	
+	auto parser = mSource->ToParser();
+
+	if ((parser != NULL) && (parser->mEmbedKind == BfSourceEmbedKind_Type))
+	{		
+		while (!isDone)
+		{
+			auto node = mVisitorPos.GetCurrent();
+			if (node == prevNode)
+			{				
+				// If we're stuck on an error and can't process any more nodes
+				break;
+			}
+			prevNode = node;
+			BfAstNode* typeMember = BfNodeDynCast<BfMemberDeclaration>(node);
+			if (typeMember == NULL)
+			{
+				SetAndRestoreValue<BfAstNode*> prevTypeMemberNodeStart(mTypeMemberNodeStart, node);
+				typeMember = ReadTypeMember(node);
+			}
+
+			//methodDeclaration->mDocumentation = FindDocumentation(methodDeclaration);
+
+			isDone = !mVisitorPos.MoveNext();
+			if (typeMember != NULL)
+			{
+				mVisitorPos.Write(typeMember);
+			}
+		}
+	}
+
+	if ((parser != NULL) && (parser->mEmbedKind == BfSourceEmbedKind_Method))
+	{
+		bool allowEndingExpression = false;
+		BfAstNode* nextNode = NULL;
+		while (!isDone)
+		{
+			BfAstNode* node = mVisitorPos.GetCurrent();
+
+			CreateStmtFlags flags = (CreateStmtFlags)(CreateStmtFlags_FindTrailingSemicolon | CreateStmtFlags_AllowLocalFunction);
+			if (allowEndingExpression)
+				flags = (CreateStmtFlags)(flags | CreateStmtFlags_AllowUnterminatedExpression);
+
+			auto statement = CreateStatement(node, flags);
+			if ((statement == NULL) && (mSource != NULL))
+				statement = mSource->CreateErrorNode(node);
+
+			isDone = !mVisitorPos.MoveNext();
+			if (statement != NULL)
+				mVisitorPos.Write(statement);
+		}
+	}
 
 	while (!isDone)
 	{
@@ -10246,7 +10299,7 @@ void BfReducer::HandleTypeDeclaration(BfTypeDeclaration* typeDecl, BfAttributeDi
 		MEMBER_SET(typeDecl, mAttributes, attributes);
 	}
 
-	if (!IsNodeRelevant(deferredHeadNode, typeDecl))
+	if ((!IsNodeRelevant(deferredHeadNode, typeDecl)) && (!typeDecl->IsTemporary()))
 	{
 		typeDecl->mIgnoreDeclaration = true;
 		return;

+ 34 - 2
IDEHelper/Compiler/BfResolvePass.cpp

@@ -18,9 +18,24 @@ BfResolvePassData::BfResolvePassData()
 	mSymbolTypeGenericParamIdx = -1;
 
 	mAutoComplete = NULL;
-	mSourceClassifier = NULL;
 	mResolveType = BfResolveType_None;
-	mParser = NULL;
+	mIsClassifying = false;
+	mHasCursorIdx = false;
+}
+
+BfResolvePassData::~BfResolvePassData()
+{
+	for (auto& emitEntryKV : mEmitEmbedEntries)
+	{
+		auto parser = emitEntryKV.mValue.mParser;
+		if (parser != NULL)
+		{
+			delete parser->mSourceClassifier;			
+			parser->mSourceClassifier = NULL;
+			parser->mParserFlags = ParserFlag_None;
+			parser->mCursorCheckIdx = -1;
+		}
+	}
 }
 
 void BfResolvePassData::RecordReplaceNode(BfParserData* parser, int srcStart, int srcLen)
@@ -179,3 +194,20 @@ void BfResolvePassData::HandleNamespaceReference(BfAstNode* node, const BfAtomCo
 			RecordReplaceNode(baseNode);
 	}
 }
+
+BfSourceClassifier* BfResolvePassData::GetSourceClassifier(BfAstNode* astNode)
+{
+	if (!mIsClassifying)
+		return NULL;
+	auto parser = astNode->GetParser();
+	if (parser == NULL)
+		return NULL;
+	return parser->mSourceClassifier;
+}
+
+BfSourceClassifier* BfResolvePassData::GetSourceClassifier(BfParser* parser)
+{
+	if (!mIsClassifying)
+		return NULL;
+	return parser->mSourceClassifier;
+}

+ 27 - 3
IDEHelper/Compiler/BfResolvePass.h

@@ -2,6 +2,7 @@
 
 #include "BfSystem.h"
 #include "BfResolvedTypeUtils.h"
+#include "BfSourceClassifier.h"
 
 NS_BF_BEGIN
 
@@ -40,17 +41,33 @@ enum BfGetSymbolReferenceKind
 	BfGetSymbolReferenceKind_Namespace
 };
 
+class BfEmitEmbedEntry
+{
+public:
+	int mCursorIdx;
+	int mRevision;
+	BfParser* mParser;
+	Array<BfSourceClassifier::CharData> mCharData;
+
+public:
+	BfEmitEmbedEntry()
+	{
+		mCursorIdx = -1;
+		mRevision = -1;
+		mParser = NULL;
+	}
+};
+
 class BfResolvePassData
 {
 public:
 	BfResolveType mResolveType;
 
-	BfParser* mParser;
+	Array<BfParser*> mParsers;
 	BfAutoComplete* mAutoComplete;
 	Array<BfTypeDef*> mAutoCompleteTempTypes; // Contains multiple values when we have nested types
 	Dictionary<BfTypeDef*, BfStaticSearch> mStaticSearchMap;
-	Dictionary<BfTypeDef*, BfInternalAccessSet> mInternalAccessMap;
-	BfSourceClassifier* mSourceClassifier;
+	Dictionary<BfTypeDef*, BfInternalAccessSet> mInternalAccessMap;	
 	Array<BfAstNode*> mExteriorAutocompleteCheckNodes;
 
 	BfGetSymbolReferenceKind mGetSymbolReferenceKind;	
@@ -64,11 +81,15 @@ public:
 	int mSymbolReferencePropertyIdx;
 	int mSymbolMethodGenericParamIdx;
 	int mSymbolTypeGenericParamIdx;
+	bool mIsClassifying;
+	bool mHasCursorIdx;
 	
 	typedef Dictionary<BfParserData*, String> FoundSymbolReferencesParserDataMap;
 	FoundSymbolReferencesParserDataMap mFoundSymbolReferencesParserData;
 	//std::vector<BfIdentifierNode*> mSymbolReferenceIdentifiers;
 
+	Dictionary<String, BfEmitEmbedEntry> mEmitEmbedEntries;
+
 public:
 	void RecordReplaceNode(BfParserData* parser, int srcStart, int srcLen);
 	void RecordReplaceNode(BfAstNode* node);	
@@ -76,6 +97,7 @@ public:
 
 public:
 	BfResolvePassData();
+	~BfResolvePassData();
 
 	void HandleLocalReference(BfIdentifierNode* identifier, BfTypeDef* typeDef, BfMethodDef* methodDef, int localVarIdx);
 	void HandleLocalReference(BfIdentifierNode* identifier, BfIdentifierNode* origNameNode, BfTypeDef* typeDef, BfMethodDef* methodDef, int localVarIdx);
@@ -87,6 +109,8 @@ public:
 	void HandleTypeReference(BfAstNode* node, BfTypeDef* typeDef);	
 	void HandleNamespaceReference(BfAstNode* node, const BfAtomComposite& namespaceName);
 
+	BfSourceClassifier* GetSourceClassifier(BfAstNode* astNode);
+	BfSourceClassifier* GetSourceClassifier(BfParser* parser);
 	//void ReplaceIdentifiers();
 };
 

+ 2 - 7
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -57,7 +57,7 @@ enum BfTypeNameFlags : uint16
 	BfTypeNameFlag_InternalName = 0x100, // Use special delimiters to remove ambiguities (ie: '+' for inner types)	
 	BfTypeNameFlag_HideGlobalName = 0x200,
 	BfTypeNameFlag_ExtendedInfo = 0x400,
-	BfTypeNameFlag_ShortConst = 0x800
+	BfTypeNameFlag_ShortConst = 0x800	
 };
 
 enum BfMethodNameFlags : uint8
@@ -1886,12 +1886,6 @@ public:
 	void ReportMemory(MemReporter* memReporter);
 };
 
-class BfCeTypeEmitEntry
-{
-public:
-	String mEmitData;
-};
-
 class BfCeTypeInfo;
 
 // Instance of struct or class
@@ -2543,6 +2537,7 @@ class BfCustomAttribute
 {
 public:
 	BfAttributeDirective* mRef;
+	BfTypeDef* mDeclaringType;
 	BfTypeInstance* mType;
 	BfMethodDef* mCtor;
 	Array<BfIRValue> mCtorArgs;

+ 44 - 2
IDEHelper/Compiler/BfSystem.cpp

@@ -30,9 +30,19 @@ void Beefy::DoBfLog(int fileIdx, const char* fmt ...)
 
 	static BfpFile* fp[10] = { NULL };
 	static bool openedLog[10] = { false };
+	static int64 logSize[10] = { 0 };
+	static int logCount[10] = { 0 };
+
+	if (logSize[fileIdx] >= 1 * 1024 * 1024 * 1024)
+	{
+		BfpFile_Release(fp[fileIdx]);
+		openedLog[fileIdx] = false;
+	}
+
 	if (!openedLog[fileIdx])
 	{
 		openedLog[fileIdx] = true;
+		logSize[fileIdx] = 0;
 
 		char exeName[512];
 		int len = 512;
@@ -42,10 +52,16 @@ void Beefy::DoBfLog(int fileIdx, const char* fmt ...)
 		int dotPos = (int)dbgName.IndexOf('.');
 		if (dotPos != -1)
 			dbgName.RemoveToEnd(dotPos);
-		dbgName += StrFormat("_%d.txt", fileIdx);
+		dbgName += StrFormat("_%d", fileIdx);
+
+		if (logCount[fileIdx] > 0)
+			dbgName += 'B';
+
+		dbgName += ".txt";
 		
 		fp[fileIdx] = BfpFile_Create(dbgName.c_str(), BfpFileCreateKind_CreateAlways, (BfpFileCreateFlags)(BfpFileCreateFlag_Write | BfpFileCreateFlag_NoBuffering | BfpFileCreateFlag_ShareRead), BfpFileAttribute_Normal, NULL);
 		onNewLine[fileIdx] = true;
+		logCount[fileIdx]++;
 	}
 	if (fp[fileIdx] == NULL)
 		return;	
@@ -74,6 +90,8 @@ void Beefy::DoBfLog(int fileIdx, const char* fmt ...)
 	{		
 		if (strOfs + numChars > 0)
 		{
+			logSize[fileIdx] += strOfs + numChars;
+
 			BfpFile_Write(fp[fileIdx], lineStr, strOfs + numChars, -1, NULL);
 			if (lineStr[strOfs + numChars - 1] == '\n')
 				onNewLine[fileIdx] = true;
@@ -98,6 +116,7 @@ void Beefy::DoBfLog(int fileIdx, const char* fmt ...)
 	else
 		onNewLine[fileIdx] = false;
 	
+	logSize[fileIdx] += aResult.length();
 	BfpFile_Write(fp[fileIdx], aResult.c_str(), aResult.length(), -1, NULL);	
 }
 
@@ -1137,8 +1156,9 @@ bool BfPassInstance::PopOutString(String* outString)
 
 bool BfPassInstance::WantsRangeRecorded(BfSourceData* bfSource, int srcIdx, int srcLen, bool isWarning, bool isDeferred)
 {
-	if ((mFilterErrorsTo != NULL) && (bfSource != mFilterErrorsTo->mSourceData))
+	if ((!mFilterErrorsTo.IsEmpty()) && (!mFilterErrorsTo.Contains(bfSource)))
 		return false;
+
 	if (bfSource == NULL)
 		return true;
 
@@ -3964,6 +3984,28 @@ BF_EXPORT void BfResolvePassData_SetDocumentationRequest(BfResolvePassData* reso
 	resolvePassData->mAutoComplete->mDocumentationEntryName = entryName;
 }
 
+BF_EXPORT void BfResolvePassData_AddEmitEmbed(BfResolvePassData* resolvePassData, char* typeName, int32 cursorIdx)
+{
+	BfEmitEmbedEntry emitEmbedEntry;
+	emitEmbedEntry.mCursorIdx = cursorIdx;
+	resolvePassData->mEmitEmbedEntries[typeName] = emitEmbedEntry;
+}
+
+BF_EXPORT void* BfResolvePassData_GetEmitEmbedData(BfResolvePassData* resolvePassData, char* typeName, int* charCount, int* revision)
+{
+	*charCount = -1;
+	*revision = 0;
+
+	BfEmitEmbedEntry* emitEmbedEntry = NULL;
+	if (!resolvePassData->mEmitEmbedEntries.TryGetValue(typeName, &emitEmbedEntry))
+		return NULL;
+	if (emitEmbedEntry->mParser == NULL)
+		return NULL;
+	*revision = emitEmbedEntry->mRevision;
+	*charCount = emitEmbedEntry->mParser->mSrcLength;
+	return emitEmbedEntry->mParser->mSourceClassifier->mCharData;
+}
+
 BF_EXPORT BfParser* BF_CALLTYPE BfSystem_CreateParser(BfSystem* bfSystem, BfProject* bfProject)
 {	
 	return bfSystem->CreateParser(bfProject);

+ 6 - 5
IDEHelper/Compiler/BfSystem.h

@@ -38,8 +38,8 @@ namespace llvm
 NS_BF_BEGIN
 
 class BfSystem;
-class BfTypeReference;
 class BfCompiler;
+class BfTypeReference;
 class BfProject;
 class BfTypeDef;
 
@@ -157,7 +157,7 @@ enum BfCompilerOptionFlags
 	BfCompilerOptionFlag_EnableSideStack    = 0x1000,
 	BfCompilerOptionFlag_EnableHotSwapping  = 0x2000,
 	BfCompilerOptionFlag_IncrementalBuild   = 0x4000,
-	BfCompilerOptionFlag_DebugAlloc         = 0x8000,
+	BfCompilerOptionFlag_DebugAlloc         = 0x8000, 
 	BfCompilerOptionFlag_OmitDebugHelpers   = 0x10000,
 	BfCompilerOptionFlag_NoFramePointerElim = 0x20000,
 	BfCompilerOptionFlag_ArithmeticChecks = 0x40000,
@@ -1412,6 +1412,7 @@ public:
 	const int sMaxErrors = 1000;
 
 	BfSystem* mSystem;
+	BfCompiler* mCompiler;
 	bool mTrimMessagesToCursor;
 	int mFailedIdx;	
 	int mWarnIdx;
@@ -1426,7 +1427,7 @@ public:
 	bool mLastWasDisplayed;
 	bool mLastWasAdded;
 	uint8 mClassifierPassId;
-	BfParser* mFilterErrorsTo;
+	HashSet<BfSourceData*> mFilterErrorsTo;
 	bool mHadSignatureChanges;
 
 public:
@@ -1436,13 +1437,13 @@ public:
 		mFailedIdx = 0;
 		mWarnIdx = 0;
 		mSystem = bfSystem;
+		mCompiler = NULL;
 		mLastWasDisplayed = false;
 		mLastWasAdded = false;
 		mClassifierPassId = 0;
 		mWarningCount = 0;		
 		mDeferredErrorCount = 0;
-		mIgnoreCount = 0;
-		mFilterErrorsTo = NULL;
+		mIgnoreCount = 0;		
 		mHadSignatureChanges = false;
 	}
 

+ 21 - 0
IDEHelper/Compiler/BfUtil.cpp

@@ -1,4 +1,5 @@
 #include "BfUtil.h"
+#include "BeefySysLib/util/Hash.h"
 
 USING_NS_BF;
 
@@ -52,6 +53,26 @@ void* Beefy::ZeroedAlloc(int size)
 	return data;
 }
 
+String Beefy::EncodeFileName(const StringImpl& fromStr)
+{
+	String path;
+	if (fromStr.mLength > 80)
+		path.Insert(0, fromStr.mPtr, 80);
+	else
+		path += fromStr;
+	
+	path.Replace("$", "\\");
+	for (auto& c : path)
+	{
+		if ((!::isalnum((uint8)c)) && (c != '_'))
+			c = '-';
+	}
+
+	path += "_";
+	path += HashEncode128(Hash128(fromStr.c_str(), (int)fromStr.length()));
+	return path;
+}
+
 uint64 stouln(const char* str, int len)
 {
 	uint64 val = 0;

+ 2 - 0
IDEHelper/Compiler/BfUtil.h

@@ -283,6 +283,8 @@ String EncodeDataPtr(uint32 addr, bool doPrefix);
 String EncodeDataPtr(uint64 addr, bool doPrefix);
 String EncodeDataPtr(int addr, bool doPrefix);
 void* ZeroedAlloc(int size);
+String EncodeFileName(const StringImpl& fromStr); // Make short, only legal chars, with a hash at end
+
 /*template <typename T>
 T* ZeroedAlloc()
 {

+ 6 - 1
IDEHelper/Compiler/CeDebugger.cpp

@@ -938,7 +938,7 @@ String CeDebugger::DoEvaluate(CePendingExpr* pendingExpr, bool inCompilerThread)
 	autoComplete.mSystem = module->mSystem;
 	
 	BfResolvePassData resolvePass;
-	resolvePass.mParser = pendingExpr->mParser;
+	resolvePass.mParsers.Add(pendingExpr->mParser);
 	resolvePass.mAutoComplete = &autoComplete;
 
 	SetAndRestoreValue<BfResolvePassData*> prevResolvePass;
@@ -4925,3 +4925,8 @@ bool CeDebugger::IsOnDemandDebugger()
 {
 	return true;
 }
+
+bool CeDebugger::GetEmitSource(const StringImpl& filePath, String& outText)
+{
+	return false;
+}

+ 1 - 0
IDEHelper/Compiler/CeDebugger.h

@@ -402,6 +402,7 @@ public:
 	virtual Profiler* PopProfiler() override; // Profiler requested by target program
 	virtual void ReportMemory(MemReporter* memReporter) override;
 	virtual bool IsOnDemandDebugger() override;
+	virtual bool GetEmitSource(const StringImpl& filePath, String& outText) override;
 };
 
 NS_BF_END

+ 31 - 0
IDEHelper/Compiler/CeMachine.h

@@ -972,11 +972,42 @@ public:
 	}
 };
 
+enum BfCeTypeEmitSourceKind
+{
+	BfCeTypeEmitSourceKind_Unknown,
+	BfCeTypeEmitSourceKind_Type,
+	BfCeTypeEmitSourceKind_Method
+};
+
+class BfCeTypeEmitSource
+{
+public:
+	BfCeTypeEmitSourceKind mKind;
+	int mSrcStart;
+	int mSrcEnd;
+
+public:
+	BfCeTypeEmitSource()
+	{
+		mKind = BfCeTypeEmitSourceKind_Unknown;
+		mSrcStart = -1;
+		mSrcEnd = -1;
+	}
+};
+
+class BfCeTypeEmitEntry
+{
+public:
+	String mEmitData;
+};
+
 class BfCeTypeInfo
 {
 public:
 	Dictionary<int, BfCeTypeEmitEntry> mOnCompileMap;
 	Dictionary<int, BfCeTypeEmitEntry> mTypeIFaceMap;
+	Dictionary<int64, BfCeTypeEmitSource> mEmitSourceMap; // key is (extension<<32)|charId
+
 	Array<int> mPendingInterfaces;
 	Dictionary<CeRebuildKey, CeRebuildValue> mRebuildMap;
 	Val128 mHash;

+ 4 - 0
IDEHelper/DbgModule.cpp

@@ -2190,6 +2190,7 @@ DbgModule::DbgModule(DebugTarget* debugTarget) : mDefaultCompileUnit(this)
 	mStartTypeIdx = 0;
 	mEndTypeIdx = 0;
 	mHotIdx = 0;
+	mId = 0;
 	mStartSubprogramIdx = 0;
 	mEndSubprogramIdx = 0;	
 	mCodeAddress = NULL;
@@ -7139,6 +7140,9 @@ DbgFileExistKind DbgModule::CheckSourceFileExist(const StringImpl& path)
 {
 	DbgFileExistKind existsKind = DbgFileExistKind_NotFound;
 
+	if (path.StartsWith("$Emit"))
+		return DbgFileExistKind_Found;
+
 	if (FileExists(path))
 		existsKind = DbgFileExistKind_Found;
 

+ 2 - 0
IDEHelper/DbgModule.h

@@ -1146,6 +1146,7 @@ public:
 	bool mMayBeOld; // If we had to load debug info from the SymCache or a SymServer then it may be old	
 	bool mDeleting;
 	bool mFailed;
+	int mId;
 	int mHotIdx;
 	String mFilePath;
 	String mDisplayName;
@@ -1226,6 +1227,7 @@ public:
 	virtual void ProcessDebugInfo();
 	virtual bool CanGetOldSource() { return false; }
 	virtual String GetOldSourceCommand(const StringImpl& path) { return ""; }
+	virtual bool GetEmitSource(const StringImpl& filePath, String& outText) { return false; }
 	virtual bool DbgIsStrMutable(const char* str) { return true; } // Always assume its a copy
 	virtual addr_target LocateSymbol(const StringImpl& name) { return 0; }
 	virtual DbgSubprogram* FindSubprogram(DbgType* dbgType, const char* methodName);

+ 13 - 0
IDEHelper/DebugManager.cpp

@@ -1609,6 +1609,19 @@ BF_EXPORT const char* BF_CALLTYPE Debugger_GetHotResolveData(uint8* outTypeData,
 	return outString.c_str();
 }
 
+BF_EXPORT const char* BF_CALLTYPE Debugger_GetEmitSource(char* inFilePath)
+{
+	AutoCrit autoCrit(gDebugManager->mCritSect);
+
+	String& outString = *gTLStrReturn.Get();
+	outString.Clear();
+
+	if (!gDebugger->GetEmitSource(inFilePath, outString))
+		return NULL;
+
+	return outString.c_str();
+}
+
 BF_EXPORT NetResult* HTTP_GetFile(char* url, char* destPath)
 {
 	AutoCrit autoCrit(gDebugManager->mNetManager->mThreadPool.mCritSect);

+ 10 - 4
IDEHelper/DebugTarget.cpp

@@ -162,14 +162,14 @@ DbgModule* DebugTarget::Init(const StringImpl& launchPath, const StringImpl& tar
 	}
 	CheckTargetBinary(dwarf);
 
-	mDbgModules.push_back(dwarf);	
+	AddDbgModule(dwarf);
 	return dwarf;
 }
 
 void DebugTarget::CreateEmptyTarget()
 {
 	auto emptyTarget = new DbgModule(this);
-	mDbgModules.push_back(emptyTarget);
+	AddDbgModule(emptyTarget);
 	mTargetBinary = emptyTarget;
 	mLaunchBinary = emptyTarget;
 }
@@ -198,7 +198,7 @@ DbgModule* DebugTarget::HotLoad(const StringImpl& fileName, int hotIdx)
 		delete dwarf;		
 		return NULL;
 	}	
-	mDbgModules.push_back(dwarf);
+	AddDbgModule(dwarf);
 	return dwarf;
 }
 
@@ -217,7 +217,7 @@ DbgModule* DebugTarget::SetupDyn(const StringImpl& filePath, DataStream* stream,
 		delete dwarf;
 		return NULL;
 	}
-	mDbgModules.push_back(dwarf);
+	AddDbgModule(dwarf);
 
 	dwarf->mDisplayName = GetFileName(filePath);
 	dwarf->mOrigImageData = new DbgModuleMemoryCache(dwarf->mImageBase, dwarf->mImageSize);
@@ -905,6 +905,12 @@ void DebugTarget::GetCompilerSettings()
 	}
 }
 
+void DebugTarget::AddDbgModule(DbgModule* dbgModule)
+{
+	static int id = 0;	
+	dbgModule->mId = ++id;
+	mDbgModules.Add(dbgModule);
+}
 
 #if 1
 bool DebugTarget::RollBackStackFrame_ExceptionDirectory(addr_target findPC, CPURegisters* registers, addr_target* outReturnAddressLoc, bool& alreadyRolledBackPC)

+ 5 - 7
IDEHelper/DebugTarget.h

@@ -37,10 +37,8 @@ public:
 	int mLastHotHeapCleanIdx;
 	String mTargetPath;
 	DbgModule* mLaunchBinary;
-	DbgModule* mTargetBinary;
-	//DbgModule* m
-	Array<DbgModule*> mDbgModules;
-	//DbgModule* mLastDWARF;
+	DbgModule* mTargetBinary;	
+	Array<DbgModule*> mDbgModules;	
 	HashSet<DbgSrcFile*> mPendingSrcFileRehup; // Waiting to remove old/invalid line info
 	
 	BumpAllocator mAlloc;	
@@ -57,12 +55,11 @@ public:
 	Array<DwCommonFrameDescriptor*> mCommonFrameDescriptors;
 	std::map<addr_target, DwFrameDescriptor> mDwFrameDescriptorMap;
 	std::map<addr_target, COFFFrameDescriptorEntry> mCOFFFrameDescriptorMap;
-	
-	//Array<DbgSrcFile*> mSrcFiles;	
+		
 	Dictionary<String, DbgSrcFile*> mSrcFiles;
 	Dictionary<String, String> mLocalToOrigSrcMap;
 
-protected:
+protected:	
 	bool RollBackStackFrame_ExceptionDirectory(addr_target findPC, CPURegisters* registers, addr_target* outReturnAddressLoc, bool& alreadyRolledBackPC);
 	bool RollBackStackFrame_ExceptionDirectory(CPURegisters* registers, addr_target* outReturnAddressLoc, bool& alreadyRolledBackPC);
 	bool RollBackStackFrame_DwFrameDescriptor(CPURegisters* registers, addr_target* outReturnAddressLoc);
@@ -76,6 +73,7 @@ public:
 	DebugTarget(WinDebugger* debugger);
 	~DebugTarget();
 	
+	void AddDbgModule(DbgModule* dbgModule);
 	DbgModule* Init(const StringImpl& launchPath, const StringImpl& targetPath, intptr imageBase = 0);
 	void SetupTargetBinary();
 	void CheckTargetBinary(DbgModule* module);

+ 2 - 1
IDEHelper/Debugger.h

@@ -351,7 +351,8 @@ public:
 	virtual Profiler* StartProfiling() = 0;
 	virtual Profiler* PopProfiler() = 0; // Profiler requested by target program
 	virtual void ReportMemory(MemReporter* memReporter) = 0;
-	virtual bool IsOnDemandDebugger() = 0;			
+	virtual bool IsOnDemandDebugger() = 0;
+	virtual bool GetEmitSource(const StringImpl& filePath, String& outText) = 0;
 };
 
 class Profiler

+ 1 - 1
IDEHelper/MiniDumpDebugger.cpp

@@ -76,7 +76,7 @@ MiniDumpDebugger::MiniDumpDebugger(DebugManager* debugManager, DbgMiniDump* mini
 
 				auto miscEntry = &mMiniDump->GetData<char>(module.MiscRecord.Rva);				
 				
-				mDebugTarget->mDbgModules.Add(dbgModule);
+				mDebugTarget->AddDbgModule(dbgModule);
 
 				//TESTING
 				/*{

+ 41 - 2
IDEHelper/WinDebugger.cpp

@@ -1531,6 +1531,24 @@ void WinDebugger::ReportMemory(MemReporter* memReporter)
 		mDebugTarget->ReportMemory(memReporter);
 }
 
+bool WinDebugger::GetEmitSource(const StringImpl& filePath, String& outText)
+{
+	if (!filePath.StartsWith("$Emit"))
+		return false;
+
+	int dollarPos = filePath.IndexOf('$', 1);
+	String numStr = filePath.Substring(5, dollarPos - 5);
+	int id = atoi(numStr.c_str());
+
+	for (auto dbgModule : mDebugTarget->mDbgModules)
+	{
+		if (dbgModule->mId == id)
+			return dbgModule->GetEmitSource(filePath, outText);
+	}
+
+	return false;
+}
+
 void WinDebugger::ModuleChanged(DbgModule* dbgModule)
 {
 	mDebugManager->mOutMessages.push_back(String("dbgInfoLoaded ") + dbgModule->mFilePath);	
@@ -11092,6 +11110,21 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o
 			*outFlags |= FrameFlags_WasHotReplaced;
 	};
 
+	auto _FixFilePath = [&](DbgModule* dbgModule)
+	{
+		if (outFile == NULL)
+			return;
+
+		if (outFile->StartsWith("$Emit"))
+		{
+			int dollarPos = outFile->IndexOf('$', 1);
+			if (dollarPos == -1)
+				return;
+
+			outFile->Insert(dollarPos, StrFormat("%d", dbgModule->mId));
+		}
+	};
+
 	if (wdStackFrame->mInInlineMethod)
 	{		
 		WdStackFrame* nextStackFrame = mCallStack[actualStackFrameIdx - 1];
@@ -11122,6 +11155,7 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o
 			*outLanguage = callingSubProgram->mCompileUnit->mLanguage;
 			auto srcFile = callingSrcFile;
 			*outFile = srcFile->GetLocalPath();
+
 			_CheckHashSrcFile(*outFile, subProgram->mCompileUnit->mDbgModule, srcFile);
 			if (*outLine == callingLineData->mLine)
 				*outColumn = callingLineData->mColumn;
@@ -11131,7 +11165,8 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o
 		DbgModule* dbgModule = wdStackFrame->mSubProgram->mCompileUnit->mDbgModule;
 		DbgModule* linkedModule = dbgModule->GetLinkedModule();
 		if (!linkedModule->mDisplayName.empty())
-			name = linkedModule->mDisplayName + "!" + name;
+			name = linkedModule->mDisplayName + "!" + name;		
+		_FixFilePath(dbgModule);
 		return name;
 	}
 	
@@ -11211,10 +11246,12 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o
 				*outDefLineEnd = dwEndLineData->mLine;
 			}
 
+			_FixFilePath(dbgModule);
 			return demangledName;
 		}
 		else
 		{
+			_FixFilePath(dbgModule);
 			return demangledName + StrFormat("+0x%X", pcAddress - dwSubprogram->mBlock.mLowPC);
 		}
 	}
@@ -11222,7 +11259,7 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o
 	{
 		String symbolName;
 		addr_target offset;
-		DbgModule* dbgModule;
+		DbgModule* dbgModule = NULL;
 		if (mDebugTarget->FindSymbolAt(pcAddress, &symbolName, &offset, &dbgModule))
 		{			
 			if (dbgModule->HasPendingDebugInfo())
@@ -11242,6 +11279,7 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o
 			String demangledName = BfDemangler::Demangle(symbolName, DbgLanguage_Unknown);
 			if (!linkedModule->mDisplayName.empty())
 				demangledName = linkedModule->mDisplayName + "!" + demangledName;
+			_FixFilePath(dbgModule);
 			return demangledName + StrFormat("+0x%X", offset);			
 		}		
 	}
@@ -11257,6 +11295,7 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o
 	String outName = EncodeDataPtr(pcAddress, true);	
 	if ((linkedModule != NULL) && (!linkedModule->mDisplayName.empty()))
 		outName = linkedModule->mDisplayName + "!" + outName;
+	_FixFilePath(dbgModule);
 	return outName;
 }
 

+ 2 - 1
IDEHelper/WinDebugger.h

@@ -657,10 +657,11 @@ public:
 	void AddProfiler(DbgProfiler* profiler);
 	void RemoveProfiler(DbgProfiler* profiler);
 
-	virtual void ReportMemory(MemReporter* memReporter) override;	
+	virtual void ReportMemory(MemReporter* memReporter) override;
 
 	virtual bool IsOnDemandDebugger() override { return false; }
 	virtual bool IsMiniDumpDebugger() { return false; }
+	virtual bool GetEmitSource(const StringImpl& filePath, String& outText);
 };
 
 template<typename T> bool WinDebugger::WriteMemory(intptr addr, T val)

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません