diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index 528609971..3f80bb699 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -81,7 +81,7 @@ void DebuggerClientListener::initUI() { } ); UITreeView* uiVariables = sdc->getUIVariables(); - uiVariables->setModel( mVariablesHolder->model ); + uiVariables->setModel( mVariablesHolder->getModel() ); uiVariables->removeEventsOfType( Event::OnModelEvent ); uiVariables->onModelEvent( [this]( const ModelEvent* modelEvent ) { if ( modelEvent->getModelEventType() == Abstract::ModelEventType::OpenTree ) { @@ -138,16 +138,18 @@ void DebuggerClientListener::debuggeeExited( int /*exitCode*/ ) { void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) { Log::debug( "DebuggerClientListener::debuggeeStopped: reason %s", event.reason ); + int threadId = mStoppedData->threadId ? *mStoppedData->threadId : 1; mStoppedData = event; - changeThread( mStoppedData->threadId ? *mStoppedData->threadId : 1 ); if ( mPausedToRefreshBreakpoints ) { mPlugin->sendPendingBreakpoints(); - mClient->resume( 1 ); + mClient->resume( threadId ); mPausedToRefreshBreakpoints = false; return; } + changeThread( mStoppedData->threadId ? *mStoppedData->threadId : 1 ); + mClient->threads(); mClient->stackTrace( mCurrentThreadId ); @@ -302,7 +304,8 @@ void DebuggerClientListener::variables( const int variablesReference, if ( mCurrentScopePos && scopeIt != mScopeRef.end() ) { ExpandedState::Location location{ mCurrentScopePos->first, mCurrentScopePos->second, mCurrentFrameId }; - mVariablesHolder->restoreExpandedState( location, mClient ); + mVariablesHolder->restoreExpandedState( location, mClient, + getStatusDebuggerController()->getUIVariables() ); } } @@ -333,6 +336,10 @@ std::optional DebuggerClientListener::getStoppedData() const { return mStoppedData; } +void DebuggerClientListener::setPausedToRefreshBreakpoints() { + mPausedToRefreshBreakpoints = true; +} + int DebuggerClientListener::getCurrentThreadId() const { return mCurrentThreadId; } diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp index b98e48a8d..82d35c773 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp @@ -57,7 +57,7 @@ class DebuggerClientListener : public DebuggerClient::Listener { std::optional getStoppedData() const; - void setPausedToRefreshBreakpoints() { mPausedToRefreshBreakpoints = true; } + void setPausedToRefreshBreakpoints(); int getCurrentThreadId() const; @@ -87,7 +87,6 @@ class DebuggerClientListener : public DebuggerClient::Listener { void changeThread( int id ); void initUI(); - }; } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index 0f335d260..1f8170c87 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -772,7 +772,7 @@ void DebuggerPlugin::buildStatusBar() { debuggerStatusElem->onWidgetCreated = [this]( StatusDebuggerController* sdc, UIWidget* ) { UITreeView* uiExpressions = sdc->getUIExpressions(); - uiExpressions->setModel( mExpressionsHolder->model ); + uiExpressions->setModel( mExpressionsHolder->getModel() ); uiExpressions->removeEventsOfType( Event::OnModelEvent ); uiExpressions->onModelEvent( [this, uiExpressions]( const ModelEvent* modelEvent ) { if ( modelEvent->getModelEventType() == Abstract::ModelEventType::OpenMenu ) { diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp index c9360c85b..798d36dd7 100644 --- a/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp @@ -1,6 +1,7 @@ #include "variablesmodel.hpp" #include "../debuggerclient.hpp" #include +#include namespace ecode { @@ -160,16 +161,16 @@ Variant VariablesModel::data( const ModelIndex& index, ModelRole role ) const { } VariablesHolder::VariablesHolder( UISceneNode* sceneNode ) : - rootNode( std::make_shared( "Root", 0 ) ), - model( std::make_shared( rootNode, sceneNode ) ) { - nodeMap[0] = rootNode; + mRootNode( std::make_shared( "Root", 0 ) ), + mModel( std::make_shared( mRootNode, sceneNode ) ) { + mNodeMap[0] = mRootNode; } void VariablesHolder::addVariables( const int variablesReference, std::vector&& vars ) { Lock l( mutex ); auto parentNode = getNodeByReference( variablesReference ); if ( !parentNode ) { - auto node = rootNode->getChildRecursive( variablesReference ); + auto node = mRootNode->getChildRecursive( variablesReference ); if ( !node ) return; parentNode = *node; @@ -187,7 +188,7 @@ void VariablesHolder::addVariables( const int variablesReference, std::vectorvar = std::move( var ); if ( child->var.variablesReference != 0 ) - nodeMap[child->var.variablesReference] = *found; + mNodeMap[child->var.variablesReference] = *found; continue; } @@ -198,72 +199,63 @@ void VariablesHolder::addVariables( const int variablesReference, std::vectoraddChild( child ); if ( child->var.variablesReference != 0 ) - nodeMap[child->var.variablesReference] = child; + mNodeMap[child->var.variablesReference] = child; } - model->invalidate( invalidateIndexes ? Model::UpdateFlag::InvalidateAllIndexes - : Model::UpdateFlag::DontInvalidateIndexes ); + mModel->invalidate( invalidateIndexes ? Model::UpdateFlag::InvalidateAllIndexes + : Model::UpdateFlag::DontInvalidateIndexes ); } void VariablesHolder::addChild( ModelVariableNode::NodePtr child ) { Lock l( mutex ); - rootNode->addChild( child ); - nodeMap[child->var.variablesReference] = child; - model->invalidate( Model::UpdateFlag::InvalidateAllIndexes ); + mRootNode->addChild( child ); + mNodeMap[child->var.variablesReference] = child; + mModel->invalidate( Model::UpdateFlag::InvalidateAllIndexes ); } void VariablesHolder::upsertRootChild( Variable&& var ) { Lock l( mutex ); - for ( size_t i = 0; i < rootNode->children.size(); i++ ) { - auto child = rootNode->children[i]; + for ( size_t i = 0; i < mRootNode->children.size(); i++ ) { + auto child = mRootNode->children[i]; if ( child->getName() == var.name ) { - auto newChild = std::make_shared( std::move( var ), rootNode ); - nodeMap[newChild->var.variablesReference] = newChild; - rootNode->children[i] = std::move( newChild ); - model->invalidate( Model::UpdateFlag::DontInvalidateIndexes ); + auto newChild = std::make_shared( std::move( var ), mRootNode ); + mNodeMap[newChild->var.variablesReference] = newChild; + mRootNode->children[i] = std::move( newChild ); + mModel->invalidate( Model::UpdateFlag::DontInvalidateIndexes ); return; } } - auto newChild = std::make_shared( std::move( var ), rootNode ); + auto newChild = std::make_shared( std::move( var ), mRootNode ); addChild( newChild ); } void VariablesHolder::clear( bool all ) { Lock l( mutex ); - rootNode->clear(); + mRootNode->clear(); if ( all ) { - nodeMap.clear(); + mNodeMap.clear(); + mExpandedStates.clear(); + mCurrentLocation = {}; } } ModelVariableNode::NodePtr VariablesHolder::getNodeByReference( int variablesReference ) { - auto it = nodeMap.find( variablesReference ); - return ( it != nodeMap.end() ) ? it->second : nullptr; + auto it = mNodeMap.find( variablesReference ); + return ( it != mNodeMap.end() ) ? it->second : nullptr; } VariablePath VariablesHolder::buildVariablePath( ModelVariableNode* node ) const { VariablePath path; - std::vector reversePath; - - // Build the path from node to root - while ( node && node != rootNode.get() ) { - reversePath.push_back( node->getName() ); + while ( node && node != mRootNode.get() ) { + path.push_back( node->getName() ); node = node->parent ? node->parent.get() : nullptr; } - - if ( reversePath.size() >= 2 ) { - path.scopeName = reversePath.back(); // The scope name is at the root - path.variableName = reversePath[reversePath.size() - 2]; // The variable name is next - - // Add any remaining path components as child path - path.childPath.assign( reversePath.begin(), reversePath.end() - 2 ); - } - + std::reverse( path.begin(), path.end() ); return path; } void VariablesHolder::saveExpandedState( const ModelIndex& index ) { - if ( !currentLocation ) + if ( !mCurrentLocation ) return; ModelVariableNode* node = static_cast( index.internalData() ); @@ -271,58 +263,51 @@ void VariablesHolder::saveExpandedState( const ModelIndex& index ) { return; auto nodePath = buildVariablePath( node ); - expandedStates[*currentLocation].insert( std::move( nodePath ) ); + mExpandedStates[*mCurrentLocation].insert( std::move( nodePath ) ); } -void VariablesHolder::restoreExpandedState( const ExpandedState::Location& location, - DebuggerClient* client ) { - currentLocation = location; +void VariablesHolder::resolvePath( std::vector path, DebuggerClient* client, + UITreeView* uiVariables, ModelVariableNode::NodePtr parentNode, + int pathPos ) { + if ( path.empty() || !parentNode ) + return; - auto it = expandedStates.find( location ); - if ( it == expandedStates.end() ) + auto currentNodeOpt = parentNode->getChild( path[pathPos] ); + if ( !currentNodeOpt ) return; - const auto& paths = it->second; + auto currentNode = *currentNodeOpt; - for ( const auto& path : paths ) { - // Find the scope node - auto scopeNode = [this, &path]() -> ModelVariableNode::NodePtr { - for ( const auto& child : rootNode->children ) { - if ( child->getName() == path.scopeName ) { - return child; - } - } - return nullptr; - }(); + if ( currentNode->getVariablesReference() > 0 ) { + const auto onVariablesRecieved = [this, uiVariables, path, currentNode, pathPos, + client]( const int variablesReference, + std::vector&& vars ) { + addVariables( variablesReference, std::move( vars ) ); - if ( !scopeNode ) - continue; + uiVariables->runOnMainThread( + [uiVariables, path] { uiVariables->selectRowWithPath( path ); } ); - // Find the variable node - auto currentNode = [&path, scopeNode]() -> ModelVariableNode::NodePtr { - for ( const auto& child : scopeNode->children ) { - if ( child->getName() == path.variableName ) { - return child; - } + auto nextPos = pathPos + 1; + if ( nextPos < static_cast( path.size() ) ) { + resolvePath( path, client, uiVariables, currentNode, nextPos ); } - return nullptr; - }(); + }; - if ( !currentNode ) - continue; + client->variables( currentNode->getVariablesReference(), Variable::Type::Both, + onVariablesRecieved ); + } +} - if ( currentNode->getVariablesReference() > 0 ) - client->variables( currentNode->getVariablesReference() ); +void VariablesHolder::restoreExpandedState( const ExpandedState::Location& location, + DebuggerClient* client, UITreeView* uiVariables ) { + mCurrentLocation = location; - for ( const auto& childName : path.childPath ) { - auto childOpt = currentNode->getChild( childName ); - if ( !childOpt ) - break; + auto it = mExpandedStates.find( location ); + if ( it == mExpandedStates.end() ) + return; - currentNode = *childOpt; - if ( currentNode->getVariablesReference() > 0 ) - client->variables( currentNode->getVariablesReference() ); - } - } + for ( const VariablePath& path : it->second ) + resolvePath( path, client, uiVariables, mRootNode, 0 ); } + } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp index 74bf72b73..0a8f776cf 100644 --- a/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp @@ -9,7 +9,8 @@ using namespace EE::UI::Models; namespace EE::UI { class UISceneNode; -} +class UITreeView; +} // namespace EE::UI namespace ecode { @@ -17,27 +18,16 @@ using namespace dap; class DebuggerClient; -struct VariablePath { - std::string scopeName; - std::string variableName; - std::vector childPath; - - bool operator==( const VariablePath& other ) const { - return scopeName == other.scopeName && variableName == other.variableName && - childPath == other.childPath; - } -}; +using VariablePath = std::vector; } // namespace ecode namespace std { template <> struct hash { size_t operator()( const ecode::VariablePath& path ) const { - size_t h = std::hash{}( path.scopeName ); - h ^= std::hash{}( path.variableName ) + 0x9e3779b9 + ( h << 6 ) + ( h >> 2 ); - for ( const auto& child : path.childPath ) { - h ^= std::hash{}( child ) + 0x9e3779b9 + ( h << 6 ) + ( h >> 2 ); - } + size_t h = 0; + for ( const auto& child : path ) + h = hashCombine( h, std::hash{}( child ) ); return h; } }; @@ -133,7 +123,8 @@ class VariablesModel : public Model { UISceneNode* mSceneNode; }; -struct VariablesHolder { +class VariablesHolder { + public: VariablesHolder( UISceneNode* sceneNode ); void addVariables( const int variablesReference, std::vector&& vars ); @@ -144,19 +135,27 @@ struct VariablesHolder { void clear( bool all = false ); - ModelVariableNode::NodePtr getNodeByReference( int variablesReference ); + void saveExpandedState( const ModelIndex& index ); + void restoreExpandedState( const ExpandedState::Location& location, DebuggerClient* client, + UITreeView* uiVariables ); + + std::shared_ptr getModel() { return mModel; } + + protected: Mutex mutex; - std::shared_ptr rootNode; - std::shared_ptr model; - std::unordered_map nodeMap; + std::shared_ptr mRootNode; + std::shared_ptr mModel; + std::unordered_map mNodeMap; + std::optional mCurrentLocation; + std::unordered_map> mExpandedStates; - std::unordered_map> expandedStates; - std::optional currentLocation; + ModelVariableNode::NodePtr getNodeByReference( int variablesReference ); VariablePath buildVariablePath( ModelVariableNode* node ) const; - void saveExpandedState( const ModelIndex& index ); - void restoreExpandedState( const ExpandedState::Location& location, DebuggerClient* client ); + + void resolvePath( std::vector path, DebuggerClient* client, + UITreeView* uiVariables, ModelVariableNode::NodePtr parentNode, int pathPos ); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index 2e54a3f92..f55db5aaa 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -2100,6 +2100,7 @@ void LSPClientPlugin::showDocumentSymbols( UICodeEditor* editor ) { if ( symbolsIt != mDocCurrentSymbols.end() ) { auto docSymbols = symbolsIt->second; std::vector path; + path.reserve( docSymbols.size() ); for ( const auto& sym : docSymbols ) path.emplace_back( sym.name ); tv->selectRowWithPath( path );