From b0d6e6153d51662eb05978e710f285ca7a1e5693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sat, 18 Jan 2025 20:09:38 -0300 Subject: [PATCH] Improve how we keep expanded variables in debugger. --- include/eepp/ui/uitreeview.hpp | 5 +- src/eepp/ui/uitreeview.cpp | 16 ++--- src/tools/ecode/ecode.cpp | 6 +- .../autocomplete/autocompleteplugin.cpp | 6 +- .../debugger/debuggerclientlistener.cpp | 18 ++++-- .../ecode/plugins/debugger/debuggerplugin.cpp | 11 +++- .../ecode/plugins/debugger/debuggerplugin.hpp | 3 +- .../debugger/models/variablesmodel.cpp | 60 +++++++++++++++---- .../debugger/models/variablesmodel.hpp | 6 +- .../ecode/plugins/lsp/lspclientplugin.cpp | 2 +- 10 files changed, 95 insertions(+), 38 deletions(-) diff --git a/include/eepp/ui/uitreeview.hpp b/include/eepp/ui/uitreeview.hpp index 1af43758b..e76955599 100644 --- a/include/eepp/ui/uitreeview.hpp +++ b/include/eepp/ui/uitreeview.hpp @@ -89,9 +89,10 @@ class EE_API UITreeView : public UIAbstractTableView { virtual ModelIndex findRowWithText( const std::string& text, const bool& caseSensitive = false, const bool& exactMatch = false ) const; - ModelIndex selectRowWithPath( std::string path ); + ModelIndex openRowWithPath( std::string path, bool selectOpenedRow = true ); - virtual ModelIndex selectRowWithPath( const std::vector& pathTree ); + virtual ModelIndex openRowWithPath( const std::vector& pathTree, + bool selectOpenedRow = true ); virtual void setSelection( const ModelIndex& index, bool scrollToSelection = true, bool openModelIndexTree = true ); diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index 77405c2e9..be8572fbe 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -155,13 +155,13 @@ void UITreeView::bindNavigationClick( UIWidget* widget ) { } bool UITreeView::tryOpenModelIndex( const ModelIndex& index, bool forceUpdate ) { - size_t rowCount = 0; + bool hasChilds = false; { ConditionalLock l( getModel() != nullptr, getModel() ? &getModel()->resourceMutex() : nullptr ); - rowCount = getModel()->rowCount( index ); + hasChilds = getModel()->hasChilds( index ); } - if ( rowCount ) { + if ( hasChilds ) { auto& data = getIndexMetadata( index ); if ( !data.open ) { data.open = true; @@ -768,7 +768,8 @@ ModelIndex UITreeView::findRowWithText( const std::string& text, const bool& cas return foundIndex; } -ModelIndex UITreeView::selectRowWithPath( const std::vector& pathTree ) { +ModelIndex UITreeView::openRowWithPath( const std::vector& pathTree, + bool selectOpenedRow ) { const Model* model = getModel(); if ( !model || !model->hasChilds() ) return {}; @@ -798,19 +799,20 @@ ModelIndex UITreeView::selectRowWithPath( const std::vector& pathTr parentIndex = foundIndex; if ( i == pathTree.size() - 1 ) { - setSelection( foundIndex ); + if ( selectOpenedRow ) + setSelection( foundIndex ); return foundIndex; } } return {}; } -ModelIndex UITreeView::selectRowWithPath( std::string path ) { +ModelIndex UITreeView::openRowWithPath( std::string path, bool selectOpenedRow ) { String::replaceAll( path, "\\", "/" ); auto pathTree = String::split( path, "/" ); if ( pathTree.empty() ) return {}; - return selectRowWithPath( pathTree ); + return openRowWithPath( pathTree, selectOpenedRow ); } void UITreeView::setSelection( const ModelIndex& index, bool scrollToSelection, diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 88da28298..af67e96d1 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1382,9 +1382,9 @@ void App::syncProjectTreeWithEditor( UICodeEditor* editor ) { std::string path = !loadingPath.empty() ? loadingPath : editor->getDocument().getFilePath(); mProjectTreeView->setFocusOnSelection( false ); if ( !mCurrentProject.empty() && String::startsWith( path, mCurrentProject ) ) { - mProjectTreeView->selectRowWithPath( path.substr( mCurrentProject.size() ) ); + mProjectTreeView->openRowWithPath( path.substr( mCurrentProject.size() ) ); } else { - mProjectTreeView->selectRowWithPath( FileSystem::fileNameFromPath( path ) ); + mProjectTreeView->openRowWithPath( FileSystem::fileNameFromPath( path ) ); } mProjectTreeView->setFocusOnSelection( true ); } @@ -2828,7 +2828,7 @@ void App::newFolder( const FileInfo& file ) { return; std::string nfp( newFolderPath ); FileSystem::filePathRemoveBasePath( mFileSystemModel->getRootPath(), nfp ); - mProjectTreeView->selectRowWithPath( nfp ); + mProjectTreeView->openRowWithPath( nfp ); }, Milliseconds( 100 ) ); } diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp index 142530825..1dc5bc162 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp @@ -1305,6 +1305,7 @@ void AutoCompletePlugin::resetSignatureHelp() { } AutoCompletePlugin::SymbolsList AutoCompletePlugin::getDocumentSymbols( TextDocument* doc ) { + static constexpr auto MAX_LINE_LENGTH = EE_1KB * 10; LuaPattern pattern( mSymbolPattern ); AutoCompletePlugin::SymbolsList symbols; if ( doc->linesCount() == 0 || doc->isHuge() || mShuttingDown ) @@ -1312,7 +1313,10 @@ AutoCompletePlugin::SymbolsList AutoCompletePlugin::getDocumentSymbols( TextDocu std::string current( getPartialSymbol( doc ) ); TextPosition end = doc->getSelection().end(); for ( Int64 i = 0; i < static_cast( doc->linesCount() ); i++ ) { - auto string = doc->line( i ).toUtf8(); + const auto& line = doc->line( i ); + if ( line.size() > MAX_LINE_LENGTH ) + continue; + auto string = line.toUtf8(); for ( auto& match : pattern.gmatch( string ) ) { std::string matchStr( match[0] ); // Ignore the symbol if is actually the current symbol being written diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index c2886c104..9ebe8c18b 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -309,10 +309,11 @@ void DebuggerClientListener::scopes( const int /*frameId*/, std::vector&& mVariablesHolder->clear(); for ( const auto& scope : scopes ) { - if ( !mPlugin->mDisplayRegisters && scope.name == "Registers" ) - continue; auto child = std::make_shared( scope.name, scope.variablesReference ); mVariablesHolder->addChild( child ); + if ( ( !mPlugin->mFetchRegisters && scope.name == "Registers" ) || + ( !mPlugin->mFetchGlobals && scope.name == "Globals" ) ) + continue; mClient->variables( scope.variablesReference ); } @@ -324,10 +325,17 @@ void DebuggerClientListener::scopes( const int /*frameId*/, std::vector&& return; auto uiVars = sdc->getUIVariables(); if ( uiVars ) { - uiVars->runOnMainThread( [uiVars] { + uiVars->runOnMainThread( [this, uiVars] { auto model = uiVars->getModel(); - for ( size_t i = 0; i < model->rowCount(); i++ ) - uiVars->setExpanded( model->index( i, 0 ), true ); + size_t total = model->rowCount(); + for ( size_t i = 0; i < total; i++ ) { + auto index = model->index( i, uiVars->getMainColumn() ); + ModelVariableNode* node = static_cast( index.internalData() ); + if ( ( !mPlugin->mFetchRegisters && node->var.name == "Registers" ) || + ( !mPlugin->mFetchGlobals && node->var.name == "Globals" ) ) + continue; + uiVars->tryOpenModelIndex( index ); + } } ); } } diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index 7ee106704..a88220a4d 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -330,10 +330,15 @@ void DebuggerPlugin::loadDAPConfig( const std::string& path, bool updateConfigFi if ( j.contains( "config" ) ) { auto& config = j["config"]; - if ( config.contains( "display_registers" ) ) - mDisplayRegisters = config.value( "display_registers", false ); + if ( config.contains( "fetch_registers" ) ) + mFetchRegisters = config.value( "fetch_registers", false ); else if ( updateConfigFile ) - config["display_registers"] = mDisplayRegisters; + config["fetch_registers"] = mFetchRegisters; + + if ( config.contains( "fetch_globals" ) ) + mFetchGlobals = config.value( "fetch_globals", false ); + else if ( updateConfigFile ) + config["fetch_globals"] = mFetchGlobals; } if ( j.contains( "dap" ) ) { diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index aefb55c42..389a10647 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -81,7 +81,8 @@ class DebuggerPlugin : public PluginBase { friend class DebuggerClientListener; bool mInitialized{ false }; - bool mDisplayRegisters{ false }; + bool mFetchRegisters{ false }; + bool mFetchGlobals{ false }; std::string mProjectPath; std::vector mDaps; diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp index 798d36dd7..9d955327b 100644 --- a/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp @@ -167,7 +167,7 @@ VariablesHolder::VariablesHolder( UISceneNode* sceneNode ) : } void VariablesHolder::addVariables( const int variablesReference, std::vector&& vars ) { - Lock l( mutex ); + Lock l( mMutex ); auto parentNode = getNodeByReference( variablesReference ); if ( !parentNode ) { auto node = mRootNode->getChildRecursive( variablesReference ); @@ -207,14 +207,14 @@ void VariablesHolder::addVariables( const int variablesReference, std::vectoraddChild( child ); mNodeMap[child->var.variablesReference] = child; mModel->invalidate( Model::UpdateFlag::InvalidateAllIndexes ); } void VariablesHolder::upsertRootChild( Variable&& var ) { - Lock l( mutex ); + Lock l( mMutex ); for ( size_t i = 0; i < mRootNode->children.size(); i++ ) { auto child = mRootNode->children[i]; if ( child->getName() == var.name ) { @@ -230,7 +230,7 @@ void VariablesHolder::upsertRootChild( Variable&& var ) { } void VariablesHolder::clear( bool all ) { - Lock l( mutex ); + Lock l( mMutex ); mRootNode->clear(); if ( all ) { mNodeMap.clear(); @@ -266,15 +266,15 @@ void VariablesHolder::saveExpandedState( const ModelIndex& index ) { mExpandedStates[*mCurrentLocation].insert( std::move( nodePath ) ); } -void VariablesHolder::resolvePath( std::vector path, DebuggerClient* client, +bool VariablesHolder::resolvePath( std::vector path, DebuggerClient* client, UITreeView* uiVariables, ModelVariableNode::NodePtr parentNode, int pathPos ) { if ( path.empty() || !parentNode ) - return; + return false; auto currentNodeOpt = parentNode->getChild( path[pathPos] ); if ( !currentNodeOpt ) - return; + return false; auto currentNode = *currentNodeOpt; @@ -285,7 +285,7 @@ void VariablesHolder::resolvePath( std::vector path, DebuggerClient addVariables( variablesReference, std::move( vars ) ); uiVariables->runOnMainThread( - [uiVariables, path] { uiVariables->selectRowWithPath( path ); } ); + [uiVariables, path] { uiVariables->openRowWithPath( path, false ); } ); auto nextPos = pathPos + 1; if ( nextPos < static_cast( path.size() ) ) { @@ -295,19 +295,55 @@ void VariablesHolder::resolvePath( std::vector path, DebuggerClient client->variables( currentNode->getVariablesReference(), Variable::Type::Both, onVariablesRecieved ); + + return true; } + + return false; +} +static int getLocationDistance( const ExpandedState::Location& loc1, + const ExpandedState::Location& loc2 ) { + if ( loc1.filePath != loc2.filePath ) + return std::numeric_limits::max(); + + if ( loc1.frameIndex != loc2.frameIndex ) { + return std::numeric_limits::max() / + 2; // Different frame but same file is better than different file + } + + return std::abs( loc1.lineNumber - loc2.lineNumber ); } -void VariablesHolder::restoreExpandedState( const ExpandedState::Location& location, +bool VariablesHolder::restoreExpandedState( const ExpandedState::Location& location, DebuggerClient* client, UITreeView* uiVariables ) { mCurrentLocation = location; auto it = mExpandedStates.find( location ); - if ( it == mExpandedStates.end() ) - return; + if ( it == mExpandedStates.end() ) { + // Find the nearest expanded state + const ExpandedState::Location* nearestLoc = nullptr; + int minDistance = std::numeric_limits::max(); + for ( const auto& state : mExpandedStates ) { + int distance = getLocationDistance( location, state.first ); + if ( distance < minDistance ) { + minDistance = distance; + nearestLoc = &state.first; + } + } + + // If we found a nearby location within reasonable distance + if ( nearestLoc != nullptr && minDistance < 1000 ) { + it = mExpandedStates.find( *nearestLoc ); + } else { + return false; // No nearby expanded state found + } + } + + bool res = true; for ( const VariablePath& path : it->second ) - resolvePath( path, client, uiVariables, mRootNode, 0 ); + res |= resolvePath( path, client, uiVariables, mRootNode, 0 ); + return res; } } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp index 0a8f776cf..f1a5f8005 100644 --- a/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp @@ -137,13 +137,13 @@ class VariablesHolder { void saveExpandedState( const ModelIndex& index ); - void restoreExpandedState( const ExpandedState::Location& location, DebuggerClient* client, + bool restoreExpandedState( const ExpandedState::Location& location, DebuggerClient* client, UITreeView* uiVariables ); std::shared_ptr getModel() { return mModel; } protected: - Mutex mutex; + Mutex mMutex; std::shared_ptr mRootNode; std::shared_ptr mModel; std::unordered_map mNodeMap; @@ -154,7 +154,7 @@ class VariablesHolder { VariablePath buildVariablePath( ModelVariableNode* node ) const; - void resolvePath( std::vector path, DebuggerClient* client, + bool resolvePath( std::vector path, DebuggerClient* client, UITreeView* uiVariables, ModelVariableNode::NodePtr parentNode, int pathPos ); }; diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index db9c36e25..16685ddd9 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -2104,7 +2104,7 @@ void LSPClientPlugin::showDocumentSymbols( UICodeEditor* editor ) { path.reserve( docSymbols.size() ); for ( const auto& sym : docSymbols ) path.emplace_back( sym.name ); - tv->selectRowWithPath( path ); + tv->openRowWithPath( path ); } }