From 4d1e14a1c3b11f67f94f807e2bf74a151f98dafd Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 16 Apr 2022 06:27:54 -0700 Subject: [PATCH] Show comptime emits as embedded sourceviews --- .../Beefy2D/src/theme/dark/DarkComboBox.bf | 35 +- .../Beefy2D/src/theme/dark/DarkEditWidget.bf | 46 +- .../Beefy2D/src/theme/dark/DarkScrollbar.bf | 4 +- BeefLibs/Beefy2D/src/widgets/EditWidget.bf | 18 +- .../Beefy2D/src/widgets/ScrollableWidget.bf | 12 +- BeefLibs/Beefy2D/src/widgets/Scrollbar.bf | 17 +- BeefLibs/Beefy2D/src/widgets/Widget.bf | 23 + BeefySysLib/BeefySysLib.vcxproj | 4 + BeefySysLib/BeefySysLib.vcxproj.filters | 15 + BeefySysLib/BeefySysLib_static.vcxproj | 4 + .../BeefySysLib_static.vcxproj.filters | 15 + BeefySysLib/Common.cpp | 6 +- BeefySysLib/util/ZipFile.cpp | 110 +++ BeefySysLib/util/ZipFile.h | 30 + IDE/src/BuildContext.bf | 11 + IDE/src/Compiler/BfCompiler.bf | 51 +- IDE/src/Compiler/BfParser.bf | 90 ++- IDE/src/Compiler/BfResolvePassData.bf | 17 + IDE/src/Debugger/DebugManager.bf | 30 +- IDE/src/IDEApp.bf | 258 ++++-- IDE/src/IDEUtils.bf | 42 + IDE/src/TestManager.bf | 1 + IDE/src/Workspace.bf | 7 + IDE/src/ui/ErrorsPanel.bf | 3 +- IDE/src/ui/OutputWidget.bf | 6 +- IDE/src/ui/QuickFind.bf | 4 - IDE/src/ui/RenameSymbolDialog.bf | 56 +- IDE/src/ui/SourceEditWidgetContent.bf | 681 +++++++++++++++- IDE/src/ui/SourceViewPanel.bf | 748 ++++++++++++++---- IDE/src/ui/StatusBar.bf | 2 + IDEHelper/COFF.cpp | 86 +- IDEHelper/COFF.h | 4 + IDEHelper/Compiler/BfAutoComplete.cpp | 64 +- IDEHelper/Compiler/BfAutoComplete.h | 1 + IDEHelper/Compiler/BfCompiler.cpp | 623 ++++++++++++--- IDEHelper/Compiler/BfCompiler.h | 4 + IDEHelper/Compiler/BfContext.cpp | 32 +- IDEHelper/Compiler/BfContext.h | 2 + IDEHelper/Compiler/BfDefBuilder.cpp | 29 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 16 +- IDEHelper/Compiler/BfModule.cpp | 77 +- IDEHelper/Compiler/BfModule.h | 5 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 284 +++++-- IDEHelper/Compiler/BfParser.cpp | 61 +- IDEHelper/Compiler/BfParser.h | 12 +- IDEHelper/Compiler/BfReducer.cpp | 57 +- IDEHelper/Compiler/BfResolvePass.cpp | 36 +- IDEHelper/Compiler/BfResolvePass.h | 30 +- IDEHelper/Compiler/BfResolvedTypeUtils.h | 9 +- IDEHelper/Compiler/BfSystem.cpp | 46 +- IDEHelper/Compiler/BfSystem.h | 11 +- IDEHelper/Compiler/BfUtil.cpp | 21 + IDEHelper/Compiler/BfUtil.h | 2 + IDEHelper/Compiler/CeDebugger.cpp | 7 +- IDEHelper/Compiler/CeDebugger.h | 1 + IDEHelper/Compiler/CeMachine.h | 31 + IDEHelper/DbgModule.cpp | 4 + IDEHelper/DbgModule.h | 2 + IDEHelper/DebugManager.cpp | 13 + IDEHelper/DebugTarget.cpp | 14 +- IDEHelper/DebugTarget.h | 12 +- IDEHelper/Debugger.h | 3 +- IDEHelper/MiniDumpDebugger.cpp | 2 +- IDEHelper/WinDebugger.cpp | 43 +- IDEHelper/WinDebugger.h | 3 +- 65 files changed, 3360 insertions(+), 633 deletions(-) create mode 100644 BeefySysLib/util/ZipFile.cpp create mode 100644 BeefySysLib/util/ZipFile.h diff --git a/BeefLibs/Beefy2D/src/theme/dark/DarkComboBox.bf b/BeefLibs/Beefy2D/src/theme/dark/DarkComboBox.bf index 6ddd620c..538d69ca 100644 --- a/BeefLibs/Beefy2D/src/theme/dark/DarkComboBox.bf +++ b/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)) diff --git a/BeefLibs/Beefy2D/src/theme/dark/DarkEditWidget.bf b/BeefLibs/Beefy2D/src/theme/dark/DarkEditWidget.bf index dea391d6..d0dd2e33 100644 --- a/BeefLibs/Beefy2D/src/theme/dark/DarkEditWidget.bf +++ b/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 mEmbeds = new .() ~ DeleteDictionaryAndValues!(_); + public Dictionary 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); diff --git a/BeefLibs/Beefy2D/src/theme/dark/DarkScrollbar.bf b/BeefLibs/Beefy2D/src/theme/dark/DarkScrollbar.bf index 76a0a1ad..54798c76 100644 --- a/BeefLibs/Beefy2D/src/theme/dark/DarkScrollbar.bf +++ b/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; } } diff --git a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf b/BeefLibs/Beefy2D/src/widgets/EditWidget.bf index 955bc23e..f403bafb 100644 --- a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf +++ b/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)); } } diff --git a/BeefLibs/Beefy2D/src/widgets/ScrollableWidget.bf b/BeefLibs/Beefy2D/src/widgets/ScrollableWidget.bf index afa18417..e44f76e0 100644 --- a/BeefLibs/Beefy2D/src/widgets/ScrollableWidget.bf +++ b/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) diff --git a/BeefLibs/Beefy2D/src/widgets/Scrollbar.bf b/BeefLibs/Beefy2D/src/widgets/Scrollbar.bf index eaf4fad2..53f5490b 100644 --- a/BeefLibs/Beefy2D/src/widgets/Scrollbar.bf +++ b/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 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); } diff --git a/BeefLibs/Beefy2D/src/widgets/Widget.bf b/BeefLibs/Beefy2D/src/widgets/Widget.bf index 31e83fd8..2b48dd91 100644 --- a/BeefLibs/Beefy2D/src/widgets/Widget.bf +++ b/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; + } + } } diff --git a/BeefySysLib/BeefySysLib.vcxproj b/BeefySysLib/BeefySysLib.vcxproj index 5a38ca1f..d9ee8d82 100644 --- a/BeefySysLib/BeefySysLib.vcxproj +++ b/BeefySysLib/BeefySysLib.vcxproj @@ -1624,6 +1624,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"TurnOffAllWarnings TurnOffAllWarnings + Level1 Level1 @@ -1950,6 +1951,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\" + @@ -2133,6 +2135,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\" + @@ -2190,6 +2193,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\" + diff --git a/BeefySysLib/BeefySysLib.vcxproj.filters b/BeefySysLib/BeefySysLib.vcxproj.filters index c82a47af..3b2dc190 100644 --- a/BeefySysLib/BeefySysLib.vcxproj.filters +++ b/BeefySysLib/BeefySysLib.vcxproj.filters @@ -75,6 +75,9 @@ {b85b0989-3047-46e9-93d7-5bc352fb0df7} + + {a159b9ee-1a71-44f5-a412-1e01e20b70c7} + @@ -722,6 +725,12 @@ src\util + + src\third_party\miniz + + + src\util + @@ -1108,6 +1117,12 @@ src\util + + src\third_party\miniz + + + src\util + diff --git a/BeefySysLib/BeefySysLib_static.vcxproj b/BeefySysLib/BeefySysLib_static.vcxproj index 3cd1d3e7..e81e9e3a 100644 --- a/BeefySysLib/BeefySysLib_static.vcxproj +++ b/BeefySysLib/BeefySysLib_static.vcxproj @@ -677,6 +677,7 @@ Level1 Level1 + Level1 Level1 @@ -883,6 +884,7 @@ + @@ -1007,6 +1009,7 @@ + @@ -1049,6 +1052,7 @@ + diff --git a/BeefySysLib/BeefySysLib_static.vcxproj.filters b/BeefySysLib/BeefySysLib_static.vcxproj.filters index 481a1346..34f64889 100644 --- a/BeefySysLib/BeefySysLib_static.vcxproj.filters +++ b/BeefySysLib/BeefySysLib_static.vcxproj.filters @@ -66,6 +66,9 @@ {1309f90f-4745-4623-ab21-5d7b1450103c} + + {d32cb9b0-e79b-49fe-82e2-33302be0baf6} + @@ -575,6 +578,12 @@ src\util + + src\util + + + src\third_party\miniz + @@ -883,6 +892,12 @@ src\util + + src\util + + + src\third_party\miniz + diff --git a/BeefySysLib/Common.cpp b/BeefySysLib/Common.cpp index 7d89b374..b8591244 100644 --- a/BeefySysLib/Common.cpp +++ b/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; diff --git a/BeefySysLib/util/ZipFile.cpp b/BeefySysLib/util/ZipFile.cpp new file mode 100644 index 00000000..5ea4ad61 --- /dev/null +++ b/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 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& 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; +} \ No newline at end of file diff --git a/BeefySysLib/util/ZipFile.h b/BeefySysLib/util/ZipFile.h new file mode 100644 index 00000000..d6841f2a --- /dev/null +++ b/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 data); + bool Get(const StringImpl& fileName, Array& data); +}; + + +NS_BF_END \ No newline at end of file diff --git a/IDE/src/BuildContext.bf b/IDE/src/BuildContext.bf index 1e9c3635..ef475142 100644 --- a/IDE/src/BuildContext.bf +++ b/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); diff --git a/IDE/src/Compiler/BfCompiler.bf b/IDE/src/Compiler/BfCompiler.bf index 8114eca9..35bd121f 100644 --- a/IDE/src/Compiler/BfCompiler.bf +++ b/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); + } } } diff --git a/IDE/src/Compiler/BfParser.bf b/IDE/src/Compiler/BfParser.bf index 5bf14ae8..0493b244 100644 --- a/IDE/src/Compiler/BfParser.bf +++ b/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 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); diff --git a/IDE/src/Compiler/BfResolvePassData.bf b/IDE/src/Compiler/BfResolvePassData.bf index eb48a844..3860ef4f 100644 --- a/IDE/src/Compiler/BfResolvePassData.bf +++ b/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); + } } } diff --git a/IDE/src/Debugger/DebugManager.bf b/IDE/src/Debugger/DebugManager.bf index c20213f3..a31e0757 100644 --- a/IDE/src/Debugger/DebugManager.bf +++ b/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 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; + } } } diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 5b67e03f..9b20dbd8 100644 --- a/IDE/src/IDEApp.bf +++ b/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 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 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); diff --git a/IDE/src/IDEUtils.bf b/IDE/src/IDEUtils.bf index c79c5bcb..b915ca2f 100644 --- a/IDE/src/IDEUtils.bf +++ b/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(' '); diff --git a/IDE/src/TestManager.bf b/IDE/src/TestManager.bf index a9541a64..57b178db 100644 --- a/IDE/src/TestManager.bf +++ b/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); diff --git a/IDE/src/Workspace.bf b/IDE/src/Workspace.bf index 26858afb..f510cdf8 100644 --- a/IDE/src/Workspace.bf +++ b/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); } diff --git a/IDE/src/ui/ErrorsPanel.bf b/IDE/src/ui/ErrorsPanel.bf index 8001dc90..baff80f3 100644 --- a/IDE/src/ui/ErrorsPanel.bf +++ b/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(); diff --git a/IDE/src/ui/OutputWidget.bf b/IDE/src/ui/OutputWidget.bf index c50c4a8e..20c031bb 100644 --- a/IDE/src/ui/OutputWidget.bf +++ b/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); diff --git a/IDE/src/ui/QuickFind.bf b/IDE/src/ui/QuickFind.bf index 9a6fa6e8..442d819b 100644 --- a/IDE/src/ui/QuickFind.bf +++ b/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() diff --git a/IDE/src/ui/RenameSymbolDialog.bf b/IDE/src/ui/RenameSymbolDialog.bf index cba9800e..830becf9 100644 --- a/IDE/src/ui/RenameSymbolDialog.bf +++ b/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); } diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 648f61db..74fe0532 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/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 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 findStrs = null; + if (mGenericTypeFilter != null) + findStrs = scope:: List(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 mPersistentTextPositions = new List() ~ DeleteContainerAndItems!(_); @@ -225,6 +613,19 @@ namespace IDE.ui public int32 mCollapseParseRevision; public int32 mCollapseTextVersionId; public List mCollapseData = new .() ~ delete _; + public List mEmitData = new .() ~ delete _; + public List 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 mCollapseMap = new .() ~ delete _; public List mOrderedCollapseEntries = new .() ~ delete _; + public List 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 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); } - } } diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index 0cca9c22..64cb8790 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -92,6 +92,30 @@ namespace IDE.ui base.MouseDown(x, y, btn, btnCount); } + public override void MouseWheel(float x, float y, float deltaX, float deltaY) + { + var sewc = mEditWidgetContent as SourceEditWidgetContent; + if ((sewc.mSourceViewPanel != null) && (sewc.mSourceViewPanel.mEmbedParent != null)) + { + if (mHasFocus) + { + if ((mVertScrollbar != null) && (mVertScrollbar.mAllowMouseWheel)) + { + mVertScrollbar.MouseWheel(x, y, 0, deltaY); + return; + } + } + + var target = sewc.mSourceViewPanel.mEmbedParent.mEditWidget.mEditWidgetContent; + SelfToOtherTranslate(target, x, y, var transX, var transY); + target.MouseWheel(transX, transY, deltaX, deltaY); + return; + } + + + base.MouseWheel(x, y, deltaX, deltaY); + } + public override void GotFocus() { //Debug.WriteLine("SourceViewPanel.GotFocus {0}", this); @@ -111,6 +135,16 @@ namespace IDE.ui mPanel.mLastFocusTick = IDEApp.sApp.mUpdateCnt; mPanel.EditGotFocus(); } + + var sewc = mEditWidgetContent as SourceEditWidgetContent; + if ((sewc.mSourceViewPanel != null) && (sewc.mSourceViewPanel.mEmbedParent != null)) + { + mVertScrollbar.mAllowMouseWheel = true; + mHorzScrollbar.mAllowMouseWheel = true; + } + + DeleteAndNullify!(gApp.mDeferredShowSource); + base.GotFocus(); } @@ -118,6 +152,14 @@ namespace IDE.ui { if (mPanel != null) mPanel.EditLostFocus(); + + var sewc = mEditWidgetContent as SourceEditWidgetContent; + if ((sewc.mSourceViewPanel != null) && (sewc.mSourceViewPanel.mEmbedParent != null)) + { + mVertScrollbar.mAllowMouseWheel = false; + mHorzScrollbar.mAllowMouseWheel = false; + } + base.LostFocus(); } @@ -329,6 +371,15 @@ namespace IDE.ui public IdSpan mCharIdSpan ~ _.Dispose(); } + class QueuedEmitShowData + { + public int32 mPrevCollapseParseRevision; + public int32 mTypeId = -1; + public String mTypeName ~ delete _; + public int32 mLine; + public int32 mColumn; + } + public class SourceViewPanel : TextPanel { enum SourceDisplayId @@ -352,6 +403,8 @@ namespace IDE.ui public bool mTrackedTextElementViewListDirty; public String mFilePath ~ delete _; public int32 mEmitRevision = -1; + public SourceEmbedKind mEmbedKind; + public SourceViewPanel mEmbedParent; public bool mIsBinary; public String mAliasFilePath ~ delete _; #if IDE_C_SUPPORT @@ -384,6 +437,8 @@ namespace IDE.ui #endif CollapseRegionView mCollapseRegionView = new .() ~ delete _; QueuedCollapseData mQueuedCollapseData ~ delete _; + QueuedEmitShowData mQueuedEmitShowData ~ delete _; + List mExplicitEmitTypes = new .() ~ DeleteContainerAndItems!(_); public EditWidgetContent.CharData[] mProcessSpellCheckCharData ~ delete _; public IdSpan mProcessSpellCheckCharIdSpan ~ _.Dispose(); @@ -569,13 +624,17 @@ namespace IDE.ui } } - public this() - { + public this(SourceEmbedKind embedKind = .None) + { + mEmbedKind = embedKind; DebugManager debugManager = IDEApp.sApp.mDebugger; debugManager.mBreakpointsChangedDelegate.Add(new => BreakpointsChanged); - mNavigationBar = new NavigationBar(this); - AddWidget(mNavigationBar); + if (mEmbedKind == .None) + { + mNavigationBar = new NavigationBar(this); + AddWidget(mNavigationBar); + } } public ~this() @@ -812,7 +871,7 @@ namespace IDE.ui { var clangCompiler = ClangResolveCompiler; clangCompiler.QueueFileRemoved(mFilePath); - if (mClangSource != null) + if (mClangSource != null) mClangSource = null; mDidClangSource = false; } @@ -989,6 +1048,17 @@ namespace IDE.ui if ((IDEApp.sApp.mSymbolReferenceHelper != null) && (IDEApp.sApp.mSymbolReferenceHelper.HasStarted) && (IDEApp.sApp.mSymbolReferenceHelper.mKind == SymbolReferenceHelper.Kind.Rename)) return false; + if (mEmbedKind != .None) + { + if ((mEmbedParent != null) && + ((resolveType == .GoToDefinition) || (resolveType == .GetCurrentLocation))) + { + mEmbedParent.Classify(resolveType, resolveParams); + } + + return true; + } + //Debug.WriteLine("Classify({0})", resolveType); if (!mIsSourceCode) @@ -1107,7 +1177,8 @@ namespace IDE.ui bool doBackground = (useResolveType == ResolveType.Classify) || (useResolveType == ResolveType.ClassifyFullRefresh); if (mAsyncAutocomplete) { - if ((useResolveType == .Autocomplete) || (useResolveType == .GetCurrentLocation) || (useResolveType == .GetSymbolInfo) || (useResolveType == .GetResultString)) + if ((useResolveType == .Autocomplete) || (useResolveType == .GetCurrentLocation) || (useResolveType == .GetSymbolInfo) || + (useResolveType == .GetResultString) || (useResolveType == .GoToDefinition)) doBackground = true; } @@ -1166,6 +1237,64 @@ namespace IDE.ui #endif } + let ewc = (SourceEditWidgetContent)mEditWidget.mEditWidgetContent; + + void FindEmbeds(ResolveParams resolveParams) + { + HashSet foundEditData = scope .(); + Dictionary remappedTypeNames = scope .(); + + for (var embed in ewc.mEmbeds.Values) + { + if (var emitEmbed = embed as SourceEditWidgetContent.EmitEmbed) + { + if (emitEmbed.mView != null) + { + var embedSourceViewPanel = emitEmbed.mView.mSourceViewPanel; + bool embedHasFocus = embedSourceViewPanel.mEditWidget.mHasFocus; + + if (!embedHasFocus) + { + if ((useResolveType != .Classify) && (useResolveType != .ClassifyFullRefresh)) + continue; + } + + if (foundEditData.Add(embedSourceViewPanel.mEditData)) + { + ResolveParams.Embed embedSource = new .(); + + String useTypeName = emitEmbed.mTypeName; + if (!mExplicitEmitTypes.IsEmpty) + { + if (remappedTypeNames.TryAdd(useTypeName, var keyPtr, var valuePtr)) + { + *valuePtr = useTypeName; + for (var explicitTypeName in mExplicitEmitTypes) + { + if (IDEUtils.GenericEquals(useTypeName, explicitTypeName)) + { + *valuePtr = explicitTypeName; + break; + } + } + } + useTypeName = *valuePtr; + } + + embedSource.mTypeName = new .(useTypeName); + if (embedHasFocus) + embedSource.mCursorIdx = (.)embedSourceViewPanel.mEditWidget.mEditWidgetContent.CursorTextPos; + else + embedSource.mCursorIdx = -1; + resolveParams.mEmitEmbeds.Add(embedSource); + + //embedSource.mParser = bfSystem.FindParser(embedSourceViewPanel.mProjectSource); + } + } + } + } + } + if (doBackground) { ProcessDeferredResolveResults(0); @@ -1176,6 +1305,8 @@ namespace IDE.ui resolveParams = new ResolveParams(); } + FindEmbeds(resolveParams); + resolveParams.mResolveType = resolveType; resolveParams.mWaitEvent = new WaitEvent(); resolveParams.mInDeferredList = true; @@ -1184,7 +1315,6 @@ namespace IDE.ui var autoComplete = GetAutoComplete(); if ((autoComplete != null) && (autoComplete.mIsDocumentationPass)) { - let ewc = (SourceEditWidgetContent)mEditWidget.mEditWidgetContent; Debug.Assert(ewc.mAutoComplete != null); let selectedEntry = ewc.mAutoComplete.mAutoCompleteListWidget.mEntryList[ewc.mAutoComplete.mAutoCompleteListWidget.mSelectIdx]; resolveParams.mDocumentationName = new String(selectedEntry.mEntryDisplay); @@ -1205,15 +1335,20 @@ namespace IDE.ui bfSystem.PerfZoneStart("DoBackground"); //ProcessResolveData(); + bool hasFocus = mEditWidget.mHasFocus; + //Debug.Assert(mProcessResolveCharData == null); DuplicateEditState(out resolveParams.mCharData, out resolveParams.mCharIdSpan); //Debug.WriteLine("Edit State: {0}", mProcessResolveCharData); - if ((useResolveType == .Autocomplete) || (useResolveType == .GetSymbolInfo) || (mIsClang)) + if (hasFocus) { - resolveParams.mOverrideCursorPos = (.)mEditWidget.Content.CursorTextPos; - /*if (useResolveType == .Autocomplete) - resolveParams.mOverrideCursorPos--;*/ + if ((useResolveType == .Autocomplete) || (useResolveType == .GetSymbolInfo) || (mIsClang)) + { + resolveParams.mOverrideCursorPos = (.)mEditWidget.Content.CursorTextPos; + /*if (useResolveType == .Autocomplete) + resolveParams.mOverrideCursorPos--;*/ + } } //Debug.Assert(mCurParser == null); @@ -1272,6 +1407,12 @@ namespace IDE.ui } else if ((mIsBeefSource) && (hasValidProjectSource)) { + var resolveParams; + if (resolveParams == null) + resolveParams = scope:: ResolveParams(); + + FindEmbeds(resolveParams); + /*if (useResolveType == ResolveType.Autocomplete) { Profiler.StartSampling(); @@ -1356,7 +1497,10 @@ namespace IDE.ui parser.SetIsClassifying(); parser.Parse(passInstance, !mIsBeefSource); if (mIsBeefSource) + { + parser.SetEmbedKind(mEmbedKind); parser.Reduce(passInstance); + } parser.ClassifySource(char8Data, !mIsBeefSource); mWantsParserCleanup = true; } @@ -1674,11 +1818,13 @@ namespace IDE.ui if (resolveType == ResolveType.GetSymbolInfo) { if (!resolveParams.mCancelled) - gApp.mSymbolReferenceHelper.SetSymbolInfo(autocompleteInfo); + gApp.mSymbolReferenceHelper?.SetSymbolInfo(autocompleteInfo); } else if (resolveType == ResolveType.GoToDefinition) { - var autocompleteLines = String.StackSplit!(autocompleteInfo, '\n'); + if (!resolveParams.mCancelled) + gApp.mSymbolReferenceHelper?.SetSymbolInfo(autocompleteInfo); + /*var autocompleteLines = String.StackSplit!(autocompleteInfo, '\n'); for (var autocompleteLine in autocompleteLines) { var lineData = String.StackSplit!(autocompleteLine, '\t'); @@ -1688,7 +1834,7 @@ namespace IDE.ui resolveParams.mOutLineChar = int32.Parse(lineData[3]); resolveParams.mOutFileName = new String(lineData[1]); } - } + }*/ } else if (resolveType == ResolveType.GetNavigationData) { @@ -1765,7 +1911,7 @@ namespace IDE.ui var bfCompiler = BfResolveCompiler; //var compiler = ResolveCompiler; - bool isBackground = (resolveType == ResolveType.Classify) || (resolveType == ResolveType.ClassifyFullRefresh) || (resolveType == .GetResultString); + bool isBackground = (resolveType == .Classify) || (resolveType == .ClassifyFullRefresh) || (resolveType == .GetResultString) || (resolveType == .GoToDefinition); bool fullRefresh = resolveType == ResolveType.ClassifyFullRefresh; if (!isBackground) @@ -1790,32 +1936,51 @@ namespace IDE.ui if (isInterrupt) bfSystem.NotifyWillRequestLock(1); + bool isFastClassify = false; + BfParser parser; + ProjectSource projectSource = FilteredProjectSource; - bool isFastClassify = false; - BfParser parser; + int cursorPos = mEditWidget.mEditWidgetContent.CursorTextPos; + + if ((resolveParams != null) && (resolveParams.mOverrideCursorPos != -1)) + cursorPos = resolveParams.mOverrideCursorPos; + + bool emitHasCursor = false; + if (resolveParams != null) + { + for (var embed in resolveParams.mEmitEmbeds) + { + if (embed.mCursorIdx != -1) + { + emitHasCursor = true; + cursorPos = -1; + } + } + } + if ((!isBackground) && (projectSource != null)) - { - bfSystem.PerfZoneStart("CreateParser"); - parser = bfSystem.CreateParser(projectSource, false); - bfSystem.PerfZoneEnd(); - } - else if ((resolveParams != null) && (resolveParams.mParser != null)) - { - parser = bfSystem.CreateNewParserRevision(resolveParams.mParser); - } - else if (projectSource != null) + { + bfSystem.PerfZoneStart("CreateParser"); + parser = bfSystem.CreateParser(projectSource, false); + bfSystem.PerfZoneEnd(); + } + else if ((resolveParams != null) && (resolveParams.mParser != null)) + { + parser = bfSystem.CreateNewParserRevision(resolveParams.mParser); + } + else if (projectSource != null) { bfSystem.PerfZoneStart("CreateParser"); parser = bfSystem.CreateParser(projectSource, false); bfSystem.PerfZoneEnd(); } else - { - // This only happens when we're editing source that isn't in our project - isFastClassify = true; - parser = bfSystem.CreateEmptyParser((BfProject)null); - } + { + // This only happens when we're editing source that isn't in our project + isFastClassify = true; + parser = bfSystem.CreateEmptyParser((BfProject)null); + } EditWidgetContent.CharData[] charData = null; int charLen = 0; @@ -1834,23 +1999,13 @@ namespace IDE.ui /*var char8Data = (!isBackground) ? mEditWidget.Content.mData.mText : mProcessResolveCharData; int char8Len = Math.Min(char8Data.Count, mEditWidget.Content.mData.mTextLength);*/ - String passInstanceName = scope String("DoClassify "); - resolveType.ToString(passInstanceName); - if (projectSource != null) - passInstanceName.Append(":", projectSource.mName); - var passInstance = bfSystem.CreatePassInstance(passInstanceName); - passInstance.SetClassifierPassId(!isBackground ? (uint8)SourceDisplayId.AutoComplete : (uint8)SourceDisplayId.FullClassify); - if (isBackground) - { - //Debug.Assert(mProcessingPassInstance == null); - //mProcessingPassInstance = passInstance; - Debug.Assert(resolveParams.mPassInstance == null); - resolveParams.mPassInstance = passInstance; - } - if (!isBackground) bfSystem.PerfZoneStart("DoClassify.CreateChars"); - char8[] chars = new char8[charLen]; + + + //text.Append(chars, 0, chars.Count); + + char8* chars = new char8[charLen]* (?); defer delete chars; for (int32 i = 0; i < charLen; i++) { @@ -1858,64 +2013,82 @@ namespace IDE.ui chars[i] = (char8)charData[i].mChar; } - String text = scope String(); - text.Append(chars, 0, chars.Count); if (!isBackground) { bfSystem.PerfZoneEnd(); bfSystem.PerfZoneStart("SetSource"); } parser.SetIsClassifying(); - parser.SetSource(text, mFilePath); + parser.SetSource(.(chars, charLen), mFilePath); if (!isBackground) { bfSystem.PerfZoneEnd(); bfSystem.PerfZoneStart("DoClassify.DoWork"); } - int cursorPos = mEditWidget.mEditWidgetContent.CursorTextPos; + //int cursorPos = mEditWidget.mEditWidgetContent.CursorTextPos; /*if (resolveType == ResolveType.Autocomplete) cursorPos--;*/ - if (resolveParams != null) + /*if (resolveParams != null) { if (resolveParams.mOverrideCursorPos != -1) cursorPos = resolveParams.mOverrideCursorPos; - } + }*/ if ((resolveType == ResolveType.GetNavigationData) || (resolveType == ResolveType.GetFixits)) parser.SetAutocomplete(-1); else { bool setAutocomplete = ((!isBackground) && (resolveType != ResolveType.RenameSymbol)); - if ((resolveType == .Autocomplete) || (resolveType == .GetCurrentLocation) || (resolveType == .GetSymbolInfo) || (resolveType == .GetResultString)) + if ((resolveType == .Autocomplete) || (resolveType == .GetCurrentLocation) || (resolveType == .GetSymbolInfo) || + (resolveType == .GoToDefinition) || (resolveType == .GetResultString)) setAutocomplete = true; if (setAutocomplete) - parser.SetAutocomplete(Math.Max(0, cursorPos)); + { + if (emitHasCursor) + parser.SetAutocomplete(-2); + else + parser.SetAutocomplete(Math.Max(emitHasCursor ? -1 : 0, cursorPos)); + } } /*else (!isFullClassify) -- do we ever need to do this? parser.SetCursorIdx(mEditWidget.mEditWidgetContent.CursorTextPos);*/ + String passInstanceName = scope String("DoClassify "); + resolveType.ToString(passInstanceName); + if (projectSource != null) + passInstanceName.Append(":", projectSource.mName); + var passInstance = bfSystem.CreatePassInstance(passInstanceName); + passInstance.SetClassifierPassId(!isBackground ? (uint8)SourceDisplayId.AutoComplete : (uint8)SourceDisplayId.FullClassify); + if (isBackground) + { + //Debug.Assert(mProcessingPassInstance == null); + //mProcessingPassInstance = passInstance; + Debug.Assert(resolveParams.mPassInstance == null); + resolveParams.mPassInstance = passInstance; + } + bool doFuzzyAutoComplete = resolveParams?.mDoFuzzyAutoComplete ?? false; - var resolvePassData = parser.CreateResolvePassData(resolveType, doFuzzyAutoComplete); - if (resolveParams != null) - { - if (resolveParams.mLocalId != -1) - resolvePassData.SetLocalId(resolveParams.mLocalId); - if (resolveParams.mTypeDef != null) - resolvePassData.SetSymbolReferenceTypeDef(resolveParams.mTypeDef); - if (resolveParams.mFieldIdx != -1) - resolvePassData.SetSymbolReferenceFieldIdx(resolveParams.mFieldIdx); - if (resolveParams.mMethodIdx != -1) - resolvePassData.SetSymbolReferenceMethodIdx(resolveParams.mMethodIdx); - if (resolveParams.mPropertyIdx != -1) - resolvePassData.SetSymbolReferencePropertyIdx(resolveParams.mPropertyIdx); - } - + var resolvePassData = parser.CreateResolvePassData(resolveType, doFuzzyAutoComplete); + if (resolveParams != null) + { + if (resolveParams.mLocalId != -1) + resolvePassData.SetLocalId(resolveParams.mLocalId); + if (resolveParams.mTypeDef != null) + resolvePassData.SetSymbolReferenceTypeDef(resolveParams.mTypeDef); + if (resolveParams.mFieldIdx != -1) + resolvePassData.SetSymbolReferenceFieldIdx(resolveParams.mFieldIdx); + if (resolveParams.mMethodIdx != -1) + resolvePassData.SetSymbolReferenceMethodIdx(resolveParams.mMethodIdx); + if (resolveParams.mPropertyIdx != -1) + resolvePassData.SetSymbolReferencePropertyIdx(resolveParams.mPropertyIdx); + } + if ((resolveParams != null) && (resolveParams.mDocumentationName != null)) resolvePassData.SetDocumentationRequest(resolveParams.mDocumentationName); - parser.Parse(passInstance, !mIsBeefSource); - parser.Reduce(passInstance); + parser.Parse(passInstance, !mIsBeefSource); + parser.Reduce(passInstance); if ((mIsBeefSource) && ((resolveType == .Classify) || (resolveType == .ClassifyFullRefresh))) @@ -1924,24 +2097,24 @@ namespace IDE.ui if (!isFastClassify) gApp.mErrorsPanel.ProcessPassInstance(passInstance, .Parse); } - - if (isInterrupt) - { - bfSystem.PerfZoneEnd(); - bfSystem.PerfZoneStart("Lock"); + + if (isInterrupt) + { + bfSystem.PerfZoneEnd(); + bfSystem.PerfZoneStart("Lock"); var sw = scope Stopwatch(true); sw.Start(); - bfSystem.Lock(1); - bfSystem.PerfZoneEnd(); - } - else - { - bfSystem.Lock(0); - } + bfSystem.Lock(1); + bfSystem.PerfZoneEnd(); + } + else + { + bfSystem.Lock(0); + } + + if (!isFastClassify) + parser.BuildDefs(passInstance, resolvePassData, fullRefresh); - if (!isFastClassify) - parser.BuildDefs(passInstance, resolvePassData, fullRefresh); - // For Fixits we do want to parse the whole file but we need the cursorIdx bound still to // locate the correct fixit info if (resolveType == ResolveType.GetFixits) @@ -1956,6 +2129,8 @@ namespace IDE.ui //Debug.WriteLine("Classify Continuing."); } + //Debug.WriteLine($"Classify {resolveType}"); + /*if (resolveType == ResolveType.RenameLocalSymbol) { // We do want cursor info for replacing the symbol, we just didn't want it for reducing @@ -1965,7 +2140,58 @@ namespace IDE.ui if ((!isFastClassify) && (bfCompiler != null)) { - if (!bfCompiler.ClassifySource(passInstance, parser, resolvePassData, charData)) + parser.CreateClassifier(passInstance, resolvePassData, charData); + + if (resolveType == .ClassifyFullRefresh) + { + NOP!(); + } + + if (resolveParams != null) + { + for (var emitEmbedData in resolveParams.mEmitEmbeds) + { + resolvePassData.AddEmitEmbed(emitEmbedData.mTypeName, emitEmbedData.mCursorIdx); + } + } + + if (bfCompiler.ClassifySource(passInstance, resolvePassData)) + { + if ((resolveType == ResolveType.Classify) || (resolveType == ResolveType.ClassifyFullRefresh)) + { + String explicitEmitTypeNames = scope .(); + for (var explicitType in mExplicitEmitTypes) + { + explicitEmitTypeNames.Append(explicitType); + explicitEmitTypeNames.Append("\n"); + } + + var collapseData = bfCompiler.GetCollapseRegions(parser, resolvePassData, explicitEmitTypeNames, .. scope .()); + using (mMonitor.Enter()) + { + DeleteAndNullify!(mQueuedCollapseData); + mQueuedCollapseData = new .(); + mQueuedCollapseData.mData.Set(collapseData); + mQueuedCollapseData.mTextVersion = resolveParams.mTextVersion; + mQueuedCollapseData.mCharIdSpan = resolveParams.mCharIdSpan.Duplicate(); + } + } + + if (resolveParams != null) + { + for (var emitEmbedData in resolveParams.mEmitEmbeds) + { + var data = resolvePassData.GetEmitEmbedData(emitEmbedData.mTypeName, var srcLength, var revision); + if (srcLength > 0) + { + emitEmbedData.mCharData = new EditWidgetContent.CharData[srcLength+1] (?); + emitEmbedData.mCharData[srcLength] = default; + Internal.MemCpy(emitEmbedData.mCharData.Ptr, data, srcLength * strideof(EditWidgetContent.CharData)); + } + } + } + } + else { //DeleteAndNullify!(mProcessResolveCharData); //mProcessResolveCharIdSpan.Dispose(); @@ -1978,18 +2204,7 @@ namespace IDE.ui bfCompiler.QueueDeferredResolveAll(); } - if ((resolveType == ResolveType.Classify) || (resolveType == ResolveType.ClassifyFullRefresh)) - { - var collapseData = bfCompiler.GetCollapseRegions(parser, .. scope .()); - using (mMonitor.Enter()) - { - DeleteAndNullify!(mQueuedCollapseData); - mQueuedCollapseData = new .(); - mQueuedCollapseData.mData.Set(collapseData); - mQueuedCollapseData.mTextVersion = resolveParams.mTextVersion; - mQueuedCollapseData.mCharIdSpan = resolveParams.mCharIdSpan.Duplicate(); - } - } + parser.FinishClassifier(resolvePassData); } else { @@ -2017,7 +2232,7 @@ namespace IDE.ui //bool isAutocomplete = (resolveType == ResolveType.Autocomplete) || (resolveType == ResolveType.Autocomplete_HighPri); //if (isAutocomplete) if ((!isFastClassify) && (!isBackground) && (resolveType == ResolveType.Autocomplete)) - InjectErrors(passInstance, mEditWidget.mEditWidgetContent.mData.mText, mEditWidget.mEditWidgetContent.mData.mTextIdData.GetPrepared(), true); + InjectErrors(passInstance, mEditWidget.mEditWidgetContent.mData.mText, mEditWidget.mEditWidgetContent.mData.mTextIdData.GetPrepared(), true, false); //IDEApp.sApp.ShowPassOutput(passInstance); delete passInstance; @@ -2339,6 +2554,20 @@ namespace IDE.ui public void CloseEdit() { + var sewc = mEditWidget.mEditWidgetContent as SourceEditWidgetContent; + for (var embed in sewc.mEmbeds.Values) + { + if (var emitEmbed = embed as SourceEditWidgetContent.EmitEmbed) + { + if (emitEmbed.mView != null) + { + emitEmbed.mView.RemoveSelf(); + DeleteAndNullify!(emitEmbed.mView); + sewc.mCollapseNeedsUpdate = true; + } + } + } + mEditWidget.mPanel = null; var editWidgetContent = (SourceEditWidgetContent)mEditWidget.Content; @@ -2538,7 +2767,7 @@ namespace IDE.ui public override void EditGotFocus() { - if (mFilePath != null) + if ((mFilePath != null) && (mEmbedKind == .None)) gApp.AddToRecentDisplayedFilesList(mFilePath); if (mLoadFailed) return; @@ -2577,12 +2806,15 @@ namespace IDE.ui editData.mEditWidget = mEditWidget; } - gApp.mLastActiveSourceViewPanel = this; - gApp.mLastActivePanel = this; - - if ((gApp.mSettings.mEditorSettings.mSyncWithWorkspacePanel) && (mProjectSource != null)) + if (mEmbedKind == .None) { - SyncWithWorkspacePanel(); + gApp.mLastActiveSourceViewPanel = this; + gApp.mLastActivePanel = this; + + if ((gApp.mSettings.mEditorSettings.mSyncWithWorkspacePanel) && (mProjectSource != null)) + { + SyncWithWorkspacePanel(); + } } } @@ -2845,6 +3077,13 @@ namespace IDE.ui List GetTrackedElementList() { + if ((mEmbedKind != .None) && (mEditWidget.mEditWidgetContent.mData.mTextLength == 0)) + { + if (mTrackedTextElementViewList == null) + mTrackedTextElementViewList = new .(); + return mTrackedTextElementViewList; + } + if (mTrackedTextElementViewListDirty) { ClearTrackedElements(); @@ -3447,6 +3686,9 @@ namespace IDE.ui void InitSplitter() { + if (mEmbedKind != .None) + return; + mSplitter = new PanelSplitter(mSplitTopPanel, this); mSplitter.mSplitAction = new => SplitView; mSplitter.mUnsplitAction = new => UnsplitView; @@ -3536,7 +3778,9 @@ namespace IDE.ui editWidgetContent.Reload(mFilePath); } editWidgetContent.mIgnoreSetHistory = false; - QueueFullRefresh(false); + + if (mEmitRevision == -1) // This causes a rehup loop if there's an emission error if we don't do this check + QueueFullRefresh(false); #if IDE_C_SUPPORT mClangSourceChanged = false; #endif @@ -3661,6 +3905,12 @@ namespace IDE.ui if (mSplitTopPanel != null) return; + + if ((mProjectSource == null) && (mFilePath == null)) + { + //TODO: We don't allow splitting of new files + return; + } // User requested from menu if (mSplitter.mSplitPct <= 0) @@ -3968,7 +4218,11 @@ namespace IDE.ui if (gApp.mDebugger.mIsRunning) foundPosition = RemapActiveToCompiledLine(curCompileIdx, ref lineIdx, ref lineCharIdx); bool createNow = foundPosition || !mIsBeefSource; // Only be strict about Beef source - newBreakpoint = debugManager.CreateBreakpoint_Create(mAliasFilePath ?? mFilePath, lineIdx, lineCharIdx, -1); + + String filePath = mAliasFilePath ?? mFilePath; + if (filePath == null) + return null; + newBreakpoint = debugManager.CreateBreakpoint_Create(filePath, lineIdx, lineCharIdx, -1); newBreakpoint.mThreadId = threadId; debugManager.CreateBreakpoint_Finish(newBreakpoint, createNow); int newDrawLineNum = GetDrawLineNum(newBreakpoint); @@ -4177,13 +4431,20 @@ namespace IDE.ui float lineSpacing = ewc.mFont.GetLineSpacing(); int cursorLineNumber = mEditWidget.mEditWidgetContent.CursorLineAndColumn.mLine; - bool hiliteCurrentLine = true; + bool hiliteCurrentLine = mEditWidget.mHasFocus; var jumpEntry = ewc.mLineCoordJumpTable[Math.Clamp((int)(-mEditWidget.Content.Y / ewc.GetJumpCoordSpacing()), 0, ewc.mLineCoordJumpTable.Count - 1)]; int lineStart = jumpEntry.min; jumpEntry = ewc.mLineCoordJumpTable[Math.Clamp((int)((-mEditWidget.Content.Y + mHeight) / ewc.GetJumpCoordSpacing()), 0, ewc.mLineCoordJumpTable.Count - 1)]; int lineEnd = jumpEntry.max - 1; + if (ewc.mLineRange != null) + { + lineStart = Math.Max(lineStart, ewc.mLineRange.Value.Start); + lineEnd = Math.Min(lineEnd, ewc.mLineRange.Value.End); + lineStart = Math.Min(lineStart, lineEnd); + } + int drawLineCount = lineEnd - lineStart + 1; ewc.RefreshCollapseRegions(); @@ -4334,7 +4595,7 @@ namespace IDE.ui }*/ } - if (gApp.mSettings.mEditorSettings.mShowLineNumbers) + if ((gApp.mSettings.mEditorSettings.mShowLineNumbers) && (mEmbedKind == .None)) { String lineStr = scope String(16); using (g.PushColor(0x80FFFFFF)) @@ -4435,6 +4696,7 @@ namespace IDE.ui if (FileNameMatches(fileName)) { RemapCompiledToActiveLine(hotIdx, ref lineNum, ref column); + Image img; if (IDEApp.sApp.mDebugger.mActiveCallStackIdx == 0) { @@ -4464,19 +4726,22 @@ namespace IDE.ui doDraw = true; } + if ((lineNum < lineStart) || (lineNum >= lineEnd)) + doDraw = false; + if (doDraw) { mLinePointerDrawData.mUpdateCnt = gApp.mUpdateCnt; mLinePointerDrawData.mDebuggerContinueIdx = gApp.mDebuggerContinueIdx; g.Draw(img, mEditWidget.mX - GS!(20) - leftAdjust, - 0 + lineNum * lineSpacing); + 0 + ewc.GetLineY(lineNum, 0)); } } } } } - bool drawLock = mSplitBottomPanel == null; + bool drawLock = (mSplitBottomPanel == null) && (mEmbedKind == .None); if (drawLock) { IDEUtils.DrawLock(g, mEditWidget.mX - GS!(20), mHeight - GS!(20), IsReadOnly, mLockFlashPct); @@ -4819,7 +5084,7 @@ namespace IDE.ui mRenameSymbolDialog = symbolReferenceHelper; gApp.mSymbolReferenceHelper = symbolReferenceHelper; - BfResolveCompiler.mThreadWorkerHi.WaitForBackground(); // We need to finish up anything on the hi thread worker so we can queue this + //BfResolveCompiler.mThreadWorkerHi.WaitForBackground(); // We need to finish up anything on the hi thread worker so we can queue this symbolReferenceHelper.Init(this, symbolReferenceKind); if (!symbolReferenceHelper.mFailed) { @@ -4828,7 +5093,7 @@ namespace IDE.ui } else { - mRenameSymbolDialog.Close(); + mRenameSymbolDialog?.Close(); } if ((symbolReferenceKind == .Rename) && (let autoComplete = GetAutoComplete())) @@ -5824,12 +6089,14 @@ namespace IDE.ui bool wantsData = (!resolveResult.mCancelled) && (resolveResult.mResolveType != .GetCurrentLocation) && (resolveResult.mResolveType != .GetSymbolInfo); if (wantsData) { + bool filterErrors = !resolveResult.mEmitEmbeds.IsEmpty; + if ((resolveResult.mCharData != null) && (resolveResult.mPassInstance != null)) { bool isAutocomplete = (resolveResult.mResolveType == .Autocomplete) || (resolveResult.mResolveType == .Autocomplete_HighPri); MarkDirty(); - InjectErrors(resolveResult.mPassInstance, resolveResult.mCharData, resolveResult.mCharIdSpan, isAutocomplete); + InjectErrors(resolveResult.mPassInstance, resolveResult.mCharData, resolveResult.mCharIdSpan, isAutocomplete, filterErrors); canDoBackground = false; } @@ -5840,6 +6107,107 @@ namespace IDE.ui canDoBackground = false; } + if ((!resolveResult.mEmitEmbeds.IsEmpty) && (resolveResult.mResolveType.IsClassify)) + { + let ewc = (SourceEditWidgetContent)mEditWidget.mEditWidgetContent; + + Dictionary emitViewDict = scope .(); + Dictionary remappedTypeNames = scope .(); + + for (var embed in ewc.mEmbeds.Values) + { + if (var emitEmbed = embed as SourceEditWidgetContent.EmitEmbed) + { + String useTypeName = emitEmbed.mTypeName; + if (!mExplicitEmitTypes.IsEmpty) + { + if (remappedTypeNames.TryAdd(useTypeName, var keyPtr, var valuePtr)) + { + *valuePtr = useTypeName; + for (var explicitTypeName in mExplicitEmitTypes) + { + if (IDEUtils.GenericEquals(useTypeName, explicitTypeName)) + { + *valuePtr = explicitTypeName; + break; + } + } + } + emitEmbed.mTypeName.Set(*valuePtr); + } + + if (emitEmbed.mView != null) + emitViewDict[emitEmbed.mTypeName] = emitEmbed.mView; + } + } + + for (var embed in resolveResult.mEmitEmbeds) + { + if (embed.mCharData == null) + continue; + + if (emitViewDict.GetValue(embed.mTypeName) case .Ok(var emitEmbedView)) + { + var emitEmbed = emitEmbedView.mEmitEmbed; + + if (emitEmbedView.mEmitEmbed.mTypeName != emitEmbedView.mTypeName) + { + int focusIdx = -1; + if (emitEmbedView.mSourceViewPanel.mEditWidget.mHasFocus) + focusIdx = 0; + else if (emitEmbedView.mGenericTypeCombo?.mEditWidget.mHasFocus == true) + focusIdx = 1; + else if (emitEmbedView.mGenericMethodCombo?.mEditWidget.mHasFocus == true) + focusIdx = 2; + + emitEmbedView.RemoveSelf(); + DeleteAndNullify!(emitEmbed.mView); + + emitEmbedView = new .(emitEmbed); + emitEmbed.mView = emitEmbedView; + mEditWidget.mEditWidgetContent.AddWidget(emitEmbed.mView); + + var sewc = mEditWidget.mEditWidgetContent as SourceEditWidgetContent; + sewc.RehupLineCoords(); + + if (focusIdx == 0) + emitEmbedView.mSourceViewPanel.mEditWidget.SetFocus(); + else if (focusIdx == 1) + emitEmbedView.mGenericTypeCombo?.mEditWidget.SetFocus(); + else if (focusIdx == 2) + emitEmbedView.mGenericMethodCombo?.mEditWidget.SetFocus(); + } + + var sourceViewPanel = emitEmbedView.mSourceViewPanel; + + var embedEWC = sourceViewPanel.mEditWidget.mEditWidgetContent; + + var prevCursorLineAndColumn = embedEWC.CursorLineAndColumn; + + var editData = sourceViewPanel.mEditWidget.mEditWidgetContent.mData; + if (editData.mTextLength == 0) + DeleteAndNullify!(sourceViewPanel.mTrackedTextElementViewList); + + delete editData.mText; + editData.mText = embed.mCharData; + editData.mTextLength = (.)embed.mCharData.Count - 1; + embed.mCharData = null; + editData.mTextIdData.Dispose(); + editData.mTextIdData = IdSpan(); + editData.mNextCharId = 0; + editData.mTextIdData.Insert(0, editData.mTextLength, ref editData.mNextCharId); + + sourceViewPanel.mEditWidget.mEditWidgetContent.ContentChanged(); + + if (prevCursorLineAndColumn.mLine >= embedEWC.GetLineCount()) + embedEWC.CursorLineAndColumn = .(embedEWC.GetLineCount() - 1, prevCursorLineAndColumn.mColumn); + + sourceViewPanel.mEmitRevision = embed.mRevision; + sourceViewPanel.InjectErrors(resolveResult.mPassInstance, editData.mText, editData.mTextIdData, false, true); + } + } + } + if (resolveResult.mPassInstance != null) { MarkDirty(); @@ -5849,6 +6217,7 @@ namespace IDE.ui } } } + /*if (checkIt) Debug.Assert(data.mDisplayTypeId == 8);*/ @@ -6270,14 +6639,15 @@ namespace IDE.ui if (BFApp.sApp.mIsUpdateBatchStart) sourceEditWidgetContent.mCursorStillTicks++; - if ((gApp.mSettings.mEditorSettings.mHiliteCursorReferences) && (!gApp.mDeterministic) && (HasFocus(true)) && (mProjectSource != null) /*&& (IDEApp.sApp.mSymbolReferenceHelper == null)*/) + if ((gApp.mSettings.mEditorSettings.mHiliteCursorReferences) && (!gApp.mDeterministic) && (HasFocus(true)) && + ((mProjectSource != null) || (mEmbedKind != .None)) /*&& (IDEApp.sApp.mSymbolReferenceHelper == null)*/) { if ((mEditWidget.mHasFocus) && (mIsBeefSource) && (sourceEditWidgetContent.mCursorStillTicks == 10) && (!sourceEditWidgetContent.mCursorImplicitlyMoved) && (!sourceEditWidgetContent.mVirtualCursorPos.HasValue)) { var symbolReferenceHelper = IDEApp.sApp.mSymbolReferenceHelper; if (symbolReferenceHelper == null) { - if ((compiler != null) && (!compiler.mThreadWorkerHi.mThreadRunning)) + if ((compiler != null) && (!compiler.mThreadWorkerHi.mThreadRunning) && (mProjectSource != null)) { ShowSymbolReferenceHelper(SymbolReferenceHelper.Kind.ShowFileReferences); } @@ -6350,6 +6720,8 @@ namespace IDE.ui DeleteAndNullify!(mQueuedCollapseData); } + UpdateQueuedEmitShowData(); + if (ewc.mCollapseNeedsUpdate) ewc.UpdateCollapse(); @@ -6357,7 +6729,72 @@ namespace IDE.ui ProcessDeferredResolveResults(0); } - void InjectErrors(BfPassInstance processingPassInstance, EditWidgetContent.CharData[] processResolveCharData, IdSpan processCharIdSpan, bool keepPersistentErrors) + public void UpdateQueuedEmitShowData() + { + var compiler = ResolveCompiler; + var bfSystem = BfResolveSystem; + var ewc = (SourceEditWidgetContent)mEditWidget.Content; + + if (mQueuedEmitShowData == null) + return; + + if (mQueuedEmitShowData.mTypeId == -1) + { + if (!compiler.IsPerformingBackgroundOperation()) + { + var bfCompiler = compiler as BfCompiler; + if (bfCompiler != null) + { + bfSystem.Lock(0); + defer bfSystem.Unlock(); + + mQueuedEmitShowData.mTypeId = (.)bfCompiler.GetTypeId(mQueuedEmitShowData.mTypeName); + } + } + } + + if (mQueuedEmitShowData.mTypeId != -1) + { + Find: do + { + for (var embed in ewc.mEmbeds.Values) + { + if (var emitEmbed = embed as SourceEditWidgetContent.EmitEmbed) + { + if ((emitEmbed.mTypeName == mQueuedEmitShowData.mTypeName) && (mQueuedEmitShowData.mLine >= emitEmbed.mStartLine) && + (mQueuedEmitShowData.mLine < emitEmbed.mEndLine)) + { + if (emitEmbed.mView == null) + { + emitEmbed.mIsOpen = true; + ewc.mCollapseNeedsUpdate = true; + } + else + { + var embedEditWidget = emitEmbed.mView.mSourceViewPanel.mEditWidget; + var embedEWC = embedEditWidget.mEditWidgetContent; + if (embedEWC.mData.mTextLength > 0) + { + int idx = embedEWC.GetTextIdx(mQueuedEmitShowData.mLine, mQueuedEmitShowData.mColumn); + emitEmbed.mView.mSourceViewPanel.FocusEdit(); + emitEmbed.mView.mSourceViewPanel.ShowFileLocation(idx, .Always); + DeleteAndNullify!(mQueuedEmitShowData); + } + } + + break Find; + } + } + } + + // Couldn't find it even after a refresh + if (ewc.mCollapseParseRevision > mQueuedEmitShowData.mPrevCollapseParseRevision) + DeleteAndNullify!(mQueuedEmitShowData); + } + } + } + + void InjectErrors(BfPassInstance processingPassInstance, EditWidgetContent.CharData[] processResolveCharData, IdSpan processCharIdSpan, bool keepPersistentErrors, bool filterErrors) { if (keepPersistentErrors) { @@ -6389,6 +6826,18 @@ namespace IDE.ui { BfPassInstance.BfError bfError = new BfPassInstance.BfError(); processingPassInstance.GetErrorData(errorIdx, bfError); + + if (filterErrors) + { + bool matches = Path.Equals(bfError.mFilePath, mFilePath); + + if (!matches) + { + delete bfError; + continue; + } + } + if (!bfError.mIsDeferred) hadNonDeferredErrors = true; @@ -6478,7 +6927,7 @@ namespace IDE.ui float GetEditX() { - if (!gApp.mSettings.mEditorSettings.mShowLineNumbers) + if (!gApp.mSettings.mEditorSettings.mShowLineNumbers && (mEmbedKind == .None)) return GS!(24); var font = IDEApp.sApp.mTinyCodeFont; @@ -6492,8 +6941,11 @@ namespace IDE.ui float topY = 0; if (mSplitBottomPanel == null) { - mNavigationBar.Resize(GS!(2), 0, Math.Max(mWidth - GS!(2), 0), GS!(22)); - topY = GS!(24); + if (mNavigationBar != null) + { + mNavigationBar.Resize(GS!(2), 0, Math.Max(mWidth - GS!(2), 0), GS!(22)); + topY = GS!(24); + } } else { @@ -6526,10 +6978,10 @@ namespace IDE.ui } else if (mSplitTopPanel == null) { - mSplitter.Resize(mWidth - GS!(20), GS!(22 - 1), GS!(20), splitterHeight + GS!(2)); + mSplitter?.Resize(mWidth - GS!(20), GS!(22 - 1), GS!(20), splitterHeight + GS!(2)); } - mSplitter.SetVisible(mPanelHeader == null); + mSplitter?.SetVisible(mPanelHeader == null); float editX = GetEditX(); if (mPanelHeader != null) @@ -6591,7 +7043,7 @@ namespace IDE.ui if (lineClick >= mCollapseRegionView.mLineStart) { int relLine = lineClick - mCollapseRegionView.mLineStart; - if (relLine < mCollapseRegionView.mCollapseIndices.Count) + if ((relLine < mCollapseRegionView.mCollapseIndices.Count) && (!ewc.mOrderedCollapseEntries.IsEmpty)) { uint32 collapseVal = mCollapseRegionView.mCollapseIndices[relLine]; if ((((collapseVal & CollapseRegionView.cStartFlag) != 0) && (btnCount == 1)) || @@ -6615,7 +7067,7 @@ namespace IDE.ui float lockX = mEditWidget.mX - GS!(20); float lockY = mHeight - GS!(20); - if (Rect(lockX, lockY, GS!(20), GS!(20)).Contains(x, y)) + if ((mEmbedKind == .None) && (Rect(lockX, lockY, GS!(20), GS!(20)).Contains(x, y))) { Menu menu = new Menu(); var menuItem = menu.AddItem("Lock Editing"); @@ -6861,15 +7313,14 @@ namespace IDE.ui { if (mEmitRevision != -1) { - BfCompiler compiler = null; - if (mFilePath.Contains("$EmitR$")) - compiler = gApp.mBfResolveCompiler; - else if (mFilePath.Contains("$Emit$")) - compiler = gApp.mBfBuildCompiler; + var compiler = gApp.mBfResolveCompiler; - if (compiler != null) + if ((compiler != null) && (!compiler.IsPerformingBackgroundOperation())) { + compiler.mBfSystem.Lock(0); int32 version = compiler.GetEmitVersion(mFilePath); + compiler.mBfSystem.Unlock(); + if ((version >= 0) && (version != mEmitRevision)) { mEmitRevision = version; @@ -6879,5 +7330,38 @@ namespace IDE.ui } } + public SourceViewPanel GetFocusedEmbeddedView() + { + if (mEditWidget.mHasFocus) + return this; + + var editWidget = mWidgetWindow.mFocusWidget as SourceEditWidget; + if (editWidget != null) + { + var sewc = editWidget.mEditWidgetContent as SourceEditWidgetContent; + if (sewc.mSourceViewPanel?.mEmbedParent == this) + return sewc.mSourceViewPanel; + } + + return this; + } + + public bool AddExplicitEmitType(StringView typeName) + { + for (var checkTypeName in mExplicitEmitTypes) + { + if (IDEUtils.GenericEquals(checkTypeName, typeName)) + { + if (checkTypeName == typeName) + return false; + + checkTypeName.Set(typeName); + return true; + } + } + + mExplicitEmitTypes.Add(new .(typeName)); + return true; + } } } diff --git a/IDE/src/ui/StatusBar.bf b/IDE/src/ui/StatusBar.bf index f907e269..f2351bef 100644 --- a/IDE/src/ui/StatusBar.bf +++ b/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; diff --git a/IDEHelper/COFF.cpp b/IDEHelper/COFF.cpp index 2ae6f015..a3171009 100644 --- a/IDEHelper/COFF.cpp +++ b/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 #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 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) diff --git a/IDEHelper/COFF.h b/IDEHelper/COFF.h index 45667e26..86dc6ddf 100644 --- a/IDEHelper/COFF.h +++ b/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 mCvModuleInfo; Dictionary 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; diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 9964b222..931a4884 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -276,10 +276,15 @@ int BfAutoComplete::GetCursorIdx(BfAstNode* node) if (node == NULL) return -1; - if (!node->IsFromParser(mCompiler->mResolvePassData->mParser)) +// if (!node->IsFromParser(mCompiler->mResolvePassData->mParser)) +// return -1; + + if (node->IsTemporary()) + return false; + auto bfParser = node->GetSourceData()->ToParser(); + if (bfParser == NULL) return -1; - auto bfParser = node->GetSourceData()->ToParser(); 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 prevClassifier(mModule->mCompiler->mResolvePassData->mSourceClassifier, NULL); + SetAndRestoreValue 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()); - if (mCompiler->mResolvePassData->mSourceClassifier != NULL) - { - //TODO: Color around dots - //mCompiler->mResolvePassData->mSourceClassifier->SetElementType(identifierNode, BfSourceElementType_Namespace); - } if (auto qualifiedNameNode = BfNodeDynCast(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(memberName))) diff --git a/IDEHelper/Compiler/BfAutoComplete.h b/IDEHelper/Compiler/BfAutoComplete.h index 428f99a1..bd650988 100644 --- a/IDEHelper/Compiler/BfAutoComplete.h +++ b/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); diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index e64d5bec..0f754315 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/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 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(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(node)) + for (auto node : parser->mSidechannelRootNode->mChildArr) { - if (preprocNode->mCommand->Equals("region")) + if (auto preprocNode = BfNodeDynCast(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)) + 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 = sideNode; - conflictSplit = NULL; - } - } - else - { - if (src[sideNode->mSrcStart] == '<') - { - conflictStart = NULL; - conflictSplit = NULL; - } - else if (src[sideNode->mSrcStart] == '=') - { - if (conflictStart != NULL) - conflictSplit = sideNode; - } - else if (src[sideNode->mSrcStart] == '>') - { - if (conflictSplit != NULL) + if (src[sideNode->mSrcStart] == '<') + { + conflictStart = sideNode; + 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())); - - 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 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())); - conflictStart = NULL; conflictSplit = NULL; } + else if (src[sideNode->mSrcStart] == '=') + { + 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(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(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; + } + } } } } - 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& 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 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 prevIgnoreError(mContext->mScratchModule->mIgnoreErrors, true); + SetAndRestoreValue prevIgnoreWarnings(mContext->mScratchModule->mIgnoreWarnings, true); + SetAndRestoreValue 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*)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 prevCompilerResolvePassData(bfCompiler->mResolvePassData, resolvePassData); SetAndRestoreValue 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 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 prevCompilerResolvePassData(bfCompiler->mResolvePassData, resolvePassData); + SetAndRestoreValue prevPassInstance(bfCompiler->mPassInstance, &bfPassInstance); + + Dictionary 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 prevCompilerResolvePassData(bfCompiler->mResolvePassData, &resolvePassData); SetAndRestoreValue 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); +} diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index b694f5b0..4c6e556e 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -543,7 +543,11 @@ public: String GetTypeDefMatches(const StringImpl& searchSrc); void GetTypeDefs(const StringImpl& typeName, Array& 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); diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index ecb3dd7d..46488995 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/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 prevSkipTypeDeclaration(mCompiler->mResolvePassData->mSourceClassifier->mSkipTypeDeclarations, true); - auto classifier = mCompiler->mResolvePassData->mSourceClassifier; - classifier->mSkipMethodInternals = isAutoCompleteTempType; - classifier->Handle(typeDecl); + SetAndRestoreValue prevSkipTypeDeclaration(sourceClassifier->mSkipTypeDeclarations, true); + sourceClassifier->mSkipMethodInternals = isAutoCompleteTempType; + sourceClassifier->Handle(typeDecl); } }; diff --git a/IDEHelper/Compiler/BfContext.h b/IDEHelper/Compiler/BfContext.h index e2501b29..fe7ef4bb 100644 --- a/IDEHelper/Compiler/BfContext.h +++ b/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; diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 4514e222..fabf557f 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/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; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 0ceb9136..4ca462c5 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/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; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index cb6c085a..248f56da 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/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 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(fieldDef->mTypeRef)) && (!BfNodeIsA(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(fieldDef->mTypeRef)) && @@ -19300,12 +19313,12 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, BF_ASSERT(!methodInstance->mIRFunction.IsFake() || (methodInstance->GetImportCallKind() != BfImportCallKind_None)); } - SetAndRestoreValue prevSourceClassifier; + SetAndRestoreValue 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); } } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 895e066f..8c762354 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/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& foundAttributes, bool underlyingTypeDeferred); void CEMixin(BfAstNode* refNode, const StringImpl& src); void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 6b58326f..30272ff7 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/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(); @@ -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 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(methodInstance->mMethodDef->mMethodDeclaration); + BfAstNode* bodyNode = NULL; + if (auto methodDecl = BfNodeDynCast(methodInstance->mMethodDef->mMethodDeclaration)) + bodyNode = methodDecl->mBody; + if (!ceEmitContext.mEmitData.IsEmpty()) { - SetAndRestoreValue prevCustomAttribute(mCurMethodState->mEmitRefNode, customAttribute.mRef); - + SetAndRestoreValue 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(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(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 wantsAllNamespaceInfo = (mCompiler->mResolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Namespace) && (mCompiler->mResolvePassData->mParser == NULL); + bool wantsFileNamespaceInfo = ((sourceClassifier != NULL) || (isGetDefinition) || (mCompiler->mResolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Namespace)); + + 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(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(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 namespaceSearch; @@ -9535,7 +9672,7 @@ void BfModule::CheckTypeRefFixit(BfAstNode* typeRef, const char* appendName) std::set 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()) { diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index 9703a349..b415715d 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/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"); diff --git a/IDEHelper/Compiler/BfParser.h b/IDEHelper/Compiler/BfParser.h index 0a26e9f7..ae1637e8 100644 --- a/IDEHelper/Compiler/BfParser.h +++ b/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 diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 7598cc62..c5946b21 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/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(node); + if (typeMember == NULL) + { + SetAndRestoreValue 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; diff --git a/IDEHelper/Compiler/BfResolvePass.cpp b/IDEHelper/Compiler/BfResolvePass.cpp index e6ec65cc..c7bfcf64 100644 --- a/IDEHelper/Compiler/BfResolvePass.cpp +++ b/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; +} diff --git a/IDEHelper/Compiler/BfResolvePass.h b/IDEHelper/Compiler/BfResolvePass.h index ad1eaa18..f41c6b31 100644 --- a/IDEHelper/Compiler/BfResolvePass.h +++ b/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 mCharData; + +public: + BfEmitEmbedEntry() + { + mCursorIdx = -1; + mRevision = -1; + mParser = NULL; + } +}; + class BfResolvePassData { public: BfResolveType mResolveType; - BfParser* mParser; + Array mParsers; BfAutoComplete* mAutoComplete; Array mAutoCompleteTempTypes; // Contains multiple values when we have nested types Dictionary mStaticSearchMap; - Dictionary mInternalAccessMap; - BfSourceClassifier* mSourceClassifier; + Dictionary mInternalAccessMap; Array mExteriorAutocompleteCheckNodes; BfGetSymbolReferenceKind mGetSymbolReferenceKind; @@ -64,11 +81,15 @@ public: int mSymbolReferencePropertyIdx; int mSymbolMethodGenericParamIdx; int mSymbolTypeGenericParamIdx; + bool mIsClassifying; + bool mHasCursorIdx; typedef Dictionary FoundSymbolReferencesParserDataMap; FoundSymbolReferencesParserDataMap mFoundSymbolReferencesParserData; //std::vector mSymbolReferenceIdentifiers; + Dictionary 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(); }; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 4731604f..9da1389f 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/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 mCtorArgs; diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index aa191f9e..0ea80d90 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/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); diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 9400d8b3..0faebc06 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/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 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; } diff --git a/IDEHelper/Compiler/BfUtil.cpp b/IDEHelper/Compiler/BfUtil.cpp index eab99f78..dee396a3 100644 --- a/IDEHelper/Compiler/BfUtil.cpp +++ b/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; diff --git a/IDEHelper/Compiler/BfUtil.h b/IDEHelper/Compiler/BfUtil.h index 55f198a6..07c60fdf 100644 --- a/IDEHelper/Compiler/BfUtil.h +++ b/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 T* ZeroedAlloc() { diff --git a/IDEHelper/Compiler/CeDebugger.cpp b/IDEHelper/Compiler/CeDebugger.cpp index 85a7cf0b..95409936 100644 --- a/IDEHelper/Compiler/CeDebugger.cpp +++ b/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 prevResolvePass; @@ -4925,3 +4925,8 @@ bool CeDebugger::IsOnDemandDebugger() { return true; } + +bool CeDebugger::GetEmitSource(const StringImpl& filePath, String& outText) +{ + return false; +} diff --git a/IDEHelper/Compiler/CeDebugger.h b/IDEHelper/Compiler/CeDebugger.h index b0361c0c..920ff865 100644 --- a/IDEHelper/Compiler/CeDebugger.h +++ b/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 \ No newline at end of file diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 1d09e989..1b276712 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/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 mOnCompileMap; Dictionary mTypeIFaceMap; + Dictionary mEmitSourceMap; // key is (extension<<32)|charId + Array mPendingInterfaces; Dictionary mRebuildMap; Val128 mHash; diff --git a/IDEHelper/DbgModule.cpp b/IDEHelper/DbgModule.cpp index c4eebfd9..15ecc0a5 100644 --- a/IDEHelper/DbgModule.cpp +++ b/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; diff --git a/IDEHelper/DbgModule.h b/IDEHelper/DbgModule.h index 1bb68323..0cf5f242 100644 --- a/IDEHelper/DbgModule.h +++ b/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); diff --git a/IDEHelper/DebugManager.cpp b/IDEHelper/DebugManager.cpp index 23f6ef27..c5ddcd5b 100644 --- a/IDEHelper/DebugManager.cpp +++ b/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); diff --git a/IDEHelper/DebugTarget.cpp b/IDEHelper/DebugTarget.cpp index 3db0fd1c..843ac218 100644 --- a/IDEHelper/DebugTarget.cpp +++ b/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) diff --git a/IDEHelper/DebugTarget.h b/IDEHelper/DebugTarget.h index bc4adf85..369238a2 100644 --- a/IDEHelper/DebugTarget.h +++ b/IDEHelper/DebugTarget.h @@ -37,10 +37,8 @@ public: int mLastHotHeapCleanIdx; String mTargetPath; DbgModule* mLaunchBinary; - DbgModule* mTargetBinary; - //DbgModule* m - Array mDbgModules; - //DbgModule* mLastDWARF; + DbgModule* mTargetBinary; + Array mDbgModules; HashSet mPendingSrcFileRehup; // Waiting to remove old/invalid line info BumpAllocator mAlloc; @@ -57,12 +55,11 @@ public: Array mCommonFrameDescriptors; std::map mDwFrameDescriptorMap; std::map mCOFFFrameDescriptorMap; - - //Array mSrcFiles; + Dictionary mSrcFiles; Dictionary 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); diff --git a/IDEHelper/Debugger.h b/IDEHelper/Debugger.h index 4e716806..af7e1f3d 100644 --- a/IDEHelper/Debugger.h +++ b/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 diff --git a/IDEHelper/MiniDumpDebugger.cpp b/IDEHelper/MiniDumpDebugger.cpp index d0c002d6..5900abdc 100644 --- a/IDEHelper/MiniDumpDebugger.cpp +++ b/IDEHelper/MiniDumpDebugger.cpp @@ -76,7 +76,7 @@ MiniDumpDebugger::MiniDumpDebugger(DebugManager* debugManager, DbgMiniDump* mini auto miscEntry = &mMiniDump->GetData(module.MiscRecord.Rva); - mDebugTarget->mDbgModules.Add(dbgModule); + mDebugTarget->AddDbgModule(dbgModule); //TESTING /*{ diff --git a/IDEHelper/WinDebugger.cpp b/IDEHelper/WinDebugger.cpp index 679cf777..b57ffb9b 100644 --- a/IDEHelper/WinDebugger.cpp +++ b/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; } diff --git a/IDEHelper/WinDebugger.h b/IDEHelper/WinDebugger.h index e12f35a7..fd47ad57 100644 --- a/IDEHelper/WinDebugger.h +++ b/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 bool WinDebugger::WriteMemory(intptr addr, T val)