diff --git a/IDE/src/BookmarkManager.bf b/IDE/src/BookmarkManager.bf index bbc195f6..d5cc5f44 100644 --- a/IDE/src/BookmarkManager.bf +++ b/IDE/src/BookmarkManager.bf @@ -4,6 +4,7 @@ using System.Text; using System.Threading.Tasks; using IDE.ui; using System.Diagnostics; +using System.IO; namespace IDE { @@ -65,7 +66,7 @@ namespace IDE public List mBookmarkList = new List() ~ delete _; /// Gets or Sets whether every bookmark in this folder is disabled or not. - public bool IsDisabled + public bool AreAllDisabled { get { @@ -84,6 +85,25 @@ namespace IDE } } + public bool AreAllEnabled + { + get + { + for (var bookmark in mBookmarkList) + if (bookmark.mIsDisabled) + return false; + + return true; + } + set + { + for (var bookmark in mBookmarkList) + bookmark.mIsDisabled = !value; + + gApp.mBookmarkManager.BookmarksChanged(); + } + } + /// Adds the given bookmark to this folder. If needed, removes it from its old folder. internal void AddBookmark(Bookmark bookmark) { @@ -125,9 +145,9 @@ namespace IDE private int mBookmarkCount; /// Number of bookmarks created, used to generate the names. - private int32 _createdBookmarks; + private int32 sBookmarkId; /// Number of folders created, used to generate the names. - private int32 _createdFolders; + private int32 sFolderId; /// Gets or sets whether all bookmarks are disabled or not. public bool AllBookmarksDisabled @@ -136,7 +156,7 @@ namespace IDE { for (var folder in mBookmarkFolders) { - if (!folder.IsDisabled) + if (!folder.AreAllDisabled) return false; } @@ -146,7 +166,7 @@ namespace IDE { for (var folder in mBookmarkFolders) { - folder.IsDisabled = value; + folder.AreAllDisabled = value; } BookmarksChanged(); @@ -172,7 +192,7 @@ namespace IDE BookmarkFolder folder = new .(); if (title == null) - folder.mTitle = new $"Folder {_createdFolders++}"; + folder.mTitle = new $"Folder {++sFolderId}"; else folder.mTitle = new String(title); @@ -247,7 +267,36 @@ namespace IDE bookmark.mColumn = (int32)wantColumn; if (title == null) - bookmark.mTitle = new $"Bookmark {_createdBookmarks++}"; + { + String baseName = Path.GetFileNameWithoutExtension(fileName, .. scope .()); + + if (IDEApp.IsSourceCode(fileName)) + { + var bfSystem = IDEApp.sApp.mBfResolveSystem; + if (bfSystem != null) + { + String content = scope .(); + gApp.LoadTextFile(fileName, content).IgnoreError(); + + var parser = bfSystem.CreateEmptyParser(null); + defer delete parser; + parser.SetSource(content, fileName, -1); + var passInstance = bfSystem.CreatePassInstance(); + defer delete passInstance; + parser.Parse(passInstance, IDEApp.IsBeefFile(fileName)); + parser.Reduce(passInstance); + + String name = parser.GetLocationName(wantLineNum, wantColumn, .. scope .()); + if (!name.IsEmpty) + bookmark.mTitle = new $"#{++sBookmarkId} {name}"; + } + } + + if (bookmark.mTitle == null) + { + bookmark.mTitle = new $"#{++sBookmarkId} {baseName}"; + } + } else bookmark.mTitle = new String(title); @@ -517,5 +566,33 @@ namespace IDE MovedToBookmark(bookmark); } + + public void RecalcCurId() + { + sBookmarkId = 0; + sFolderId = 0; + + for (var folder in mBookmarkFolders) + { + if (folder.mTitle?.StartsWith("Folder ") == true) + { + if (int32 curId = int32.Parse(folder.mTitle.Substring("Folder ".Length))) + sFolderId = Math.Max(sFolderId, curId); + } + + for (var bookmark in folder.mBookmarkList) + { + if (bookmark.mTitle.StartsWith("#")) + { + int spacePos = bookmark.mTitle.IndexOf(' '); + if (spacePos != -1) + { + if (int32 curId = int32.Parse(bookmark.mTitle.Substring(1, spacePos - 1))) + sBookmarkId = Math.Max(sBookmarkId, curId); + } + } + } + } + } } } diff --git a/IDE/src/Compiler/BfParser.bf b/IDE/src/Compiler/BfParser.bf index e16a024a..fe114315 100644 --- a/IDE/src/Compiler/BfParser.bf +++ b/IDE/src/Compiler/BfParser.bf @@ -175,6 +175,9 @@ namespace IDE.Compiler [CallingConvention(.Stdcall), CLink] static extern void BfParser_SetCompleteParse(void* bfParser); + [CallingConvention(.Stdcall), CLink] + static extern char8* BfSystem_GetParserLocationName(void* bfParser, int32 line, int32 column); + public BfSystem mSystem; public void* mNativeBfParser; public bool mIsUsed; @@ -419,5 +422,12 @@ namespace IDE.Compiler var md5Hash; BfParser_SetHashMD5(mNativeBfParser, ref md5Hash); } + + public void GetLocationName(int line, int column, String outBuffer) + { + var ptr = BfSystem_GetParserLocationName(mNativeBfParser, (.)line, (.)column); + if (ptr != null) + outBuffer.Append(ptr); + } } } diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 7e70fd23..f83da07b 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -3382,6 +3382,7 @@ namespace IDE mBookmarkManager.CreateBookmark(absPath, lineNum, column, isDisabled, bookmarkTitle, folder); } } + mBookmarkManager.RecalcCurId(); for (var referenceId in data.Enumerate("DebuggerDisplayTypes")) { diff --git a/IDE/src/ui/BookmarksPanel.bf b/IDE/src/ui/BookmarksPanel.bf index 2118643b..aef6618e 100644 --- a/IDE/src/ui/BookmarksPanel.bf +++ b/IDE/src/ui/BookmarksPanel.bf @@ -124,13 +124,12 @@ namespace IDE.ui mBookmarksListView.mOnItemMouseDown.Add(new (item, x, y, btnNum, btnCount) => { + ListViewItemMouseDown(item, x, y, btnNum, btnCount); if ((btnNum == 0) && (btnCount == 2)) { let mainItem = (BookmarksListViewItem)item.GetSubItem(0); mainItem.Goto(); } - - ListViewItemMouseDown(item, x, y, btnNum, btnCount); }); mBookmarksListView.mOnItemMouseClicked.Add(new => ListViewItemMouseClicked); mBookmarksListView.mOnKeyDown.Add(new => BookmarksLV_OnKeyDown); @@ -203,10 +202,12 @@ namespace IDE.ui var target = (BookmarksListViewItem)theEvent.mDragTarget; if (source.mListView == target.mListView) - { + { if (source == target) return; + target.Open(true, true); + List selectedItems = scope .(); mBookmarksListView.GetRoot().WithSelectedItems(scope [&] (selectedItem) => { @@ -394,11 +395,11 @@ namespace IDE.ui if (mBookmarksDirty) UpdateBookmarks(); - ShowTooltip(mBtnCreateBookmarkFolder, "Create a new folder."); - ShowTooltip(mBtnPrevBookmark, "Move the cursor to the previous bookmark."); - ShowTooltip(mBtnNextBookmark, "Move the cursor to the next bookmark."); - ShowTooltip(mBtnPrevBookmarkInFolder, "Move the cursor to the previous bookmark in the current folder."); - ShowTooltip(mBtnNextBookmarkInFolder, "Move the cursor to the next bookmark in the current folder."); + ShowTooltip(mBtnCreateBookmarkFolder, "Create new folder"); + ShowTooltip(mBtnPrevBookmark, "Previous bookmark"); + ShowTooltip(mBtnNextBookmark, "Next bookmark"); + ShowTooltip(mBtnPrevBookmarkInFolder, "Previous bookmark in folder"); + ShowTooltip(mBtnNextBookmarkInFolder, "Next bookmark in folder"); base.Update(); } @@ -479,20 +480,23 @@ namespace IDE.ui private BookmarksListViewItem AddFolderToListView(BookmarksListViewItem parent, BookmarkFolder folder) { var listViewItem = (BookmarksListViewItem)parent.CreateChildItem(); - + listViewItem.MakeParent(); listViewItem.RefObject = folder; listViewItem.AllowDragging = true; var subViewItem = (DarkListViewItem)listViewItem.GetOrCreateSubItem(0); - DarkCheckBox cb = new DarkCheckBox(); - cb.Checked = !folder.IsDisabled; - cb.Resize(GS!(-16), 0, GS!(22), GS!(22)); - cb.mOnValueChanged.Add(new () => - { - folder.IsDisabled = !cb.Checked; - }); - subViewItem.AddWidget(cb); + if (!folder.mBookmarkList.IsEmpty) + { + DarkCheckBox cb = new DarkCheckBox(); + cb.State = folder.AreAllDisabled ? .Unchecked : folder.AreAllEnabled ? .Checked : .Indeterminate; + cb.Resize(GS!(-16), 0, GS!(22), GS!(22)); + cb.mOnValueChanged.Add(new () => + { + folder.AreAllEnabled = cb.State != .Unchecked; + }); + subViewItem.AddWidget(cb); + } subViewItem.Label = folder.mTitle; subViewItem.Resize(GS!(22), 0, 0, 0); @@ -516,6 +520,7 @@ namespace IDE.ui cb.mOnValueChanged.Add(new () => { bookmark.mIsDisabled = !cb.Checked; + mBookmarksDirty = true; }); subViewItem.AddWidget(cb); diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index 77d28807..4dc727e2 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -452,6 +452,26 @@ void BfParser::GetLineCharAtIdx(int idx, int& line, int& lineChar) mParserData->GetLineCharAtIdx(idx, line, lineChar); } +int BfParser::GetIndexAtLine(int line) +{ + if (line == 0) + return 0; + + int curLine = 0; + for (int i = 0; i < mSrcLength; i++) + { + char c = mSrc[i]; + if (c == '\n') + { + curLine++; + if (line == curLine) + return i; + } + } + + return -1; +} + void BfParser::Fail(const StringImpl& error, int offset) { mPassInstance->FailAt(error, mSourceData, mSrcIdx + offset); diff --git a/IDEHelper/Compiler/BfParser.h b/IDEHelper/Compiler/BfParser.h index d68f825e..b5a2b297 100644 --- a/IDEHelper/Compiler/BfParser.h +++ b/IDEHelper/Compiler/BfParser.h @@ -230,6 +230,7 @@ public: virtual BfParser* ToParser() override { return this; } void GetLineCharAtIdx(int idx, int& line, int& lineChar); + int GetIndexAtLine(int line); void Fail(const StringImpl& error, int offset = -1); void TokenFail(const StringImpl& error, int offset = -1); diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 28be7946..cd6870f0 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -4090,6 +4090,72 @@ BF_EXPORT void BF_CALLTYPE BfSystem_DeleteParser(BfSystem* bfSystem, BfParser* b //bfSystem->mParserDeleteQueue.push_back(bfParser); } +class BfLocationNameVisitor : public BfElementVisitor +{ +public: + int mIndex; + String mName; + + bool TryNode(BfAstNode* node) + { + if ((mIndex >= node->mSrcStart) && (mIndex < node->mSrcEnd)) + { + if (!mName.IsEmpty()) + mName += "."; + return true; + } + return false; + } + + virtual void Visit(BfTypeDeclaration* typeDeclaration) + { + if ((typeDeclaration->mNameNode != NULL) && (TryNode(typeDeclaration))) + { + typeDeclaration->mNameNode->ToString(mName); + } + + BfElementVisitor::Visit(typeDeclaration); + } + + virtual void Visit(BfMethodDeclaration* methodDeclaration) + { + if ((methodDeclaration->mNameNode != NULL) && (TryNode(methodDeclaration))) + { + if (methodDeclaration->mNameNode != NULL) + methodDeclaration->mNameNode->ToString(mName); + } + + BfElementVisitor::Visit(methodDeclaration); + } + + virtual void Visit(BfPropertyDeclaration* propertyDeclaration) + { + if ((propertyDeclaration->mNameNode != NULL) && (TryNode(propertyDeclaration))) + { + if (propertyDeclaration->mNameNode != NULL) + propertyDeclaration->mNameNode->ToString(mName); + } + + BfElementVisitor::Visit(propertyDeclaration); + } +}; + +BF_EXPORT const char* BfSystem_GetParserLocationName(BfParser* parser, int line, int column) +{ + int idx = parser->GetIndexAtLine(line); + if (idx == -1) + return NULL; + idx += column; + + BfLocationNameVisitor visitor; + visitor.mIndex = idx; + visitor.VisitMembers(parser->mRootNode); + + String& outString = *gTLStrReturn.Get(); + outString = visitor.mName; + return outString.c_str(); +} + BF_EXPORT BfCompiler* BF_CALLTYPE BfSystem_CreateCompiler(BfSystem* bfSystem, bool isResolveOnly) { return bfSystem->CreateCompiler(isResolveOnly);