From b340fcbbf9e17b7d67a924e161fe559704c3818b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 12 Jan 2025 00:36:14 -0300 Subject: [PATCH] Some refactor. --- projects/linux/ee.files | 6 + .../debugger/dap/debuggerclientdap.cpp | 45 +- .../debugger/dap/debuggerclientdap.hpp | 10 +- .../ecode/plugins/debugger/debuggerclient.hpp | 9 +- .../debugger/debuggerclientlistener.cpp | 404 +----------------- .../debugger/debuggerclientlistener.hpp | 7 +- .../ecode/plugins/debugger/debuggerplugin.hpp | 1 + .../plugins/debugger/models/stackmodel.cpp | 93 ++++ .../plugins/debugger/models/stackmodel.hpp | 46 ++ .../plugins/debugger/models/threadsmodel.cpp | 77 ++++ .../plugins/debugger/models/threadsmodel.hpp | 48 +++ .../debugger/models/variablesmodel.cpp | 219 ++++++++++ .../debugger/models/variablesmodel.hpp | 91 ++++ .../debugger/statusdebuggercontroller.cpp | 8 +- .../debugger/statusdebuggercontroller.hpp | 1 + 15 files changed, 648 insertions(+), 417 deletions(-) create mode 100644 src/tools/ecode/plugins/debugger/models/stackmodel.cpp create mode 100644 src/tools/ecode/plugins/debugger/models/stackmodel.hpp create mode 100644 src/tools/ecode/plugins/debugger/models/threadsmodel.cpp create mode 100644 src/tools/ecode/plugins/debugger/models/threadsmodel.hpp create mode 100644 src/tools/ecode/plugins/debugger/models/variablesmodel.cpp create mode 100644 src/tools/ecode/plugins/debugger/models/variablesmodel.hpp diff --git a/projects/linux/ee.files b/projects/linux/ee.files index dfef7250b..b40983524 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -1590,6 +1590,12 @@ ../../src/tools/ecode/plugins/debugger/debuggerplugin.hpp ../../src/tools/ecode/plugins/debugger/models/breakpointsmodel.cpp ../../src/tools/ecode/plugins/debugger/models/breakpointsmodel.hpp +../../src/tools/ecode/plugins/debugger/models/stackmodel.cpp +../../src/tools/ecode/plugins/debugger/models/stackmodel.hpp +../../src/tools/ecode/plugins/debugger/models/threadsmodel.cpp +../../src/tools/ecode/plugins/debugger/models/threadsmodel.hpp +../../src/tools/ecode/plugins/debugger/models/variablesmodel.cpp +../../src/tools/ecode/plugins/debugger/models/variablesmodel.hpp ../../src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp ../../src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp ../../src/tools/ecode/plugins/formatter/formatterplugin.cpp diff --git a/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.cpp b/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.cpp index 0ec7e0809..a3b4c74a7 100644 --- a/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.cpp +++ b/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.cpp @@ -282,17 +282,17 @@ void DebuggerClientDap::processResponse( const nlohmann::json& msg ) { Log::debug( "DebuggerClientDap::processResponse: request cancelled: %s", response.command ); if ( !response.success ) - return errorResponse( response.message, response.errorBody ); + return errorResponse( response.command, response.message, response.errorBody ); if ( request.handler ) { request.handler( response, request.arguments ); } } -void DebuggerClientDap::errorResponse( const std::string& summary, +void DebuggerClientDap::errorResponse( const std::string& command, const std::string& summary, const std::optional& message ) { for ( auto listener : mListeners ) - listener->errorResponse( summary, message ); + listener->errorResponse( command, summary, message ); } void DebuggerClientDap::processEvent( const nlohmann::json& msg ) { @@ -596,7 +596,8 @@ bool DebuggerClientDap::scopes( int frameId ) { return true; } -bool DebuggerClientDap::variables( int variablesReference, Variable::Type filter, int start, +bool DebuggerClientDap::variables( int variablesReference, Variable::Type filter, + DebuggerClient::VariablesResponseCb responseCb, int start, int count ) { nlohmann::json arguments{ { DAP_VARIABLES_REFERENCE, variablesReference }, @@ -615,20 +616,30 @@ bool DebuggerClientDap::variables( int variablesReference, Variable::Type filter break; } - makeRequest( DAP_VARIABLES, arguments, - [this]( const Response& response, const nlohmann::json& request ) { - const int variablesReference = request.value( DAP_VARIABLES_REFERENCE, 0 ); + makeRequest( + DAP_VARIABLES, arguments, + [this, responseCb = std::move( responseCb )]( const Response& response, + const nlohmann::json& request ) { + const int variablesReference = request.value( DAP_VARIABLES_REFERENCE, 0 ); - if ( response.success ) { - auto variableList( Variable::parseList( response.body[DAP_VARIABLES] ) ); - for ( auto listener : mListeners ) - listener->variables( variablesReference, std::move( variableList ) ); - } else { - std::vector variableList; - for ( auto listener : mListeners ) - listener->variables( variablesReference, std::move( variableList ) ); - } - } ); + if ( response.success ) { + auto variableList( Variable::parseList( response.body[DAP_VARIABLES] ) ); + if ( responseCb ) { + responseCb( variablesReference, std::move( variableList ) ); + } else { + for ( auto listener : mListeners ) + listener->variables( variablesReference, std::move( variableList ) ); + } + } else { + std::vector variableList; + if ( responseCb ) { + responseCb( variablesReference, std::move( variableList ) ); + } else { + for ( auto listener : mListeners ) + listener->variables( variablesReference, std::move( variableList ) ); + } + } + } ); return true; } diff --git a/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.hpp b/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.hpp index 24054af64..8e4fe44aa 100644 --- a/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.hpp +++ b/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.hpp @@ -16,8 +16,8 @@ class DebuggerClientDap : public DebuggerClient { public: typedef std::function ResponseHandler; - std::function& args, const std::string& cwd, + std::function& args, + const std::string& cwd, const std::unordered_map& env, std::function doneFn )> runInTerminalCb; @@ -51,7 +51,8 @@ class DebuggerClientDap : public DebuggerClient { bool scopes( int frameId ) override; bool variables( int variablesReference, Variable::Type filter = Variable::Type::Both, - int start = 0, int count = 0 ) override; + DebuggerClient::VariablesResponseCb responseCb = nullptr, int start = 0, + int count = 0 ) override; bool modules( int start, int count ) override; @@ -124,7 +125,8 @@ class DebuggerClientDap : public DebuggerClient { std::optional readHeader(); - void errorResponse( const std::string& summary, const std::optional& message ); + void errorResponse( const std::string& command, const std::string& summary, + const std::optional& message ); void processEventInitialized(); diff --git a/src/tools/ecode/plugins/debugger/debuggerclient.hpp b/src/tools/ecode/plugins/debugger/debuggerclient.hpp index 32f5d6baa..ea3641f39 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclient.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerclient.hpp @@ -10,6 +10,9 @@ class DebuggerClient { public: enum class State { None, Initializing, Initialized, Running, Terminated, Failed }; + using VariablesResponseCb = + std::function&& vars )>; + class Listener { public: virtual void stateChanged( State ) = 0; @@ -26,7 +29,7 @@ class DebuggerClient { virtual void debuggeeContinued( const ContinuedEvent& ) = 0; virtual void outputProduced( const Output& ) = 0; virtual void debuggingProcess( const ProcessInfo& ) = 0; - virtual void errorResponse( const std::string& summary, + virtual void errorResponse( const std::string& command, const std::string& summary, const std::optional& message ) = 0; virtual void threadChanged( const ThreadEvent& ) = 0; virtual void moduleChanged( const ModuleEvent& ) = 0; @@ -78,8 +81,10 @@ class DebuggerClient { virtual bool modules( int start, int count ) = 0; + /** if responseCb is provided, response will not be sent to listeners */ virtual bool variables( int variablesReference, Variable::Type filter = Variable::Type::Both, - int start = 0, int count = 0 ) = 0; + VariablesResponseCb responseCb = nullptr, int start = 0, + int count = 0 ) = 0; virtual bool evaluate( const std::string& expression, const std::string& context, std::optional frameId, diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index 13bd4aad7..132a9b27f 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -2,6 +2,9 @@ #include "../../notificationcenter.hpp" #include "../../statusappoutputcontroller.hpp" #include "debuggerplugin.hpp" +#include "models/stackmodel.hpp" +#include "models/threadsmodel.hpp" +#include "models/variablesmodel.hpp" namespace ecode { @@ -15,353 +18,10 @@ DebuggerClientListener::fromSet( const EE::UnorderedSet; - -struct ModelVariableNode : public std::enable_shared_from_this { - using NodePtr = std::shared_ptr; - - static std::unordered_map nodeMap; - - static NodePtr getNodeByReference( int variablesReference ) { - auto it = nodeMap.find( variablesReference ); - return ( it != nodeMap.end() ) ? it->second : nullptr; - } - - ModelVariableNode( Variable&& var, NodePtr parent ) : - parent( parent ), var( std::move( var ) ) {} - - ModelVariableNode( const std::string& name, int variablesReference, NodePtr parent = nullptr ) : - parent( parent ) { - var.name = name; - var.variablesReference = variablesReference; - } - - virtual ~ModelVariableNode() {} - - const std::vector& getChildren() const { return children; } - - const std::string& getName() const { return var.name; } - - int getVariablesReference() const { return var.variablesReference; } - - void clear() { children.clear(); } - - std::optional getChildRecursive( int variablesReference ) { - if ( var.variablesReference == variablesReference ) - return shared_from_this(); - - for ( const auto& child : children ) { - auto found = child->getChild( variablesReference ); - if ( found ) - return found; - } - return {}; - } - - std::optional getChild( const std::string& name ) { - auto found = - std::find_if( children.begin(), children.end(), - [&name]( const NodePtr& child ) { return child->var.name == name; } ); - return ( found != children.end() ) ? *found : std::optional{}; - } - - std::optional getChild( int variablesReference ) { - auto found = std::find_if( children.begin(), children.end(), - [variablesReference]( const NodePtr& child ) { - return child->var.variablesReference == variablesReference; - } ); - return ( found != children.end() ) ? *found : std::optional{}; - } - - void addChild( NodePtr child ) { children.emplace_back( child ); } - - NodePtr getParent() const { return parent; } - - NodePtr parent{ nullptr }; - Variable var; - std::vector children; -}; - -std::unordered_map ModelVariableNode::nodeMap = - std::unordered_map(); - -class VariablesModel : public Model { - public: - enum Columns { Name, Value, Type }; - - VariablesModel( ModelVariableNode::NodePtr rootNode, UISceneNode* sceneNode ) : - rootNode( rootNode ), mSceneNode( sceneNode ) {} - - ModelIndex index( int row, int column, - const ModelIndex& parent = ModelIndex() ) const override { - ModelVariableNode* parentNode = - parent.isValid() ? static_cast( parent.internalData() ) - : rootNode.get(); - - if ( row >= 0 && row < static_cast( parentNode->getChildren().size() ) ) { - ModelVariableNode::NodePtr childNode = parentNode->getChildren()[row]; - return createIndex( row, column, childNode.get() ); - } - - return ModelIndex(); - } - - ModelIndex parentIndex( const ModelIndex& index ) const override { - if ( !index.isValid() ) - return ModelIndex(); - - ModelVariableNode* childNode = static_cast( index.internalData() ); - ModelVariableNode::NodePtr parentNode = childNode->getParent(); - - if ( parentNode == nullptr || parentNode == rootNode ) - return ModelIndex(); - - ModelVariableNode::NodePtr grandParentNode = parentNode->getParent(); - if ( grandParentNode == nullptr ) - grandParentNode = rootNode; - - int row = std::distance( grandParentNode->getChildren().begin(), - std::find_if( grandParentNode->getChildren().begin(), - grandParentNode->getChildren().end(), - [parentNode]( ModelVariableNode::NodePtr node ) { - return node.get() == parentNode.get(); - } ) ); - - return createIndex( row, Columns::Name, parentNode.get() ); - } - - size_t rowCount( const ModelIndex& index = ModelIndex() ) const override { - ModelVariableNode* parentNode = - index.isValid() ? static_cast( index.internalData() ) - : rootNode.get(); - - return static_cast( parentNode->getChildren().size() ); - } - - bool hasChilds( const ModelIndex& index = ModelIndex() ) const override { - if ( !index.isValid() ) - return !rootNode->children.empty(); - ModelVariableNode* node = static_cast( index.internalData() ); - return !node->children.empty() || node->var.variablesReference > 0; - } - - size_t columnCount( const ModelIndex& ) const override { return 3; } - - std::string columnName( const size_t& colIdx ) const override { - switch ( colIdx ) { - case Columns::Name: - return mSceneNode->i18n( "variable_name", "Variable Name" ); - case Columns::Value: - return mSceneNode->i18n( "value", "Value" ); - case Columns::Type: - return mSceneNode->i18n( "type", "Type" ); - } - return ""; - } - - Variant data( const ModelIndex& index, ModelRole role ) const override { - static const char* EMPTY = ""; - if ( !index.isValid() ) - return EMPTY; - - ModelVariableNode* node = static_cast( index.internalData() ); - - if ( role == ModelRole::Display ) { - switch ( index.column() ) { - case 0: - return Variant( node->var.name.c_str() ); - case 1: - return Variant( node->var.value.c_str() ); - case 2: - return Variant( node->var.type ? node->var.type->c_str() : EMPTY ); - } - } - - return EMPTY; - } - - protected: - ModelVariableNode::NodePtr rootNode; - UISceneNode* mSceneNode; -}; - -class ThreadsModel : public Model { - public: - enum Columns { ID }; - - ThreadsModel( const std::vector& threads, UISceneNode* sceneNode ) : - mThreads( threads ), mSceneNode( sceneNode ) {} - - virtual size_t rowCount( const ModelIndex& ) const { return mThreads.size(); } - virtual size_t columnCount( const ModelIndex& ) const { return 1; } - - virtual std::string columnName( const size_t& colIdx ) const { - switch ( colIdx ) { - case Columns::ID: - return mSceneNode->i18n( "thread_id", "Thread ID" ); - } - return ""; - } - - virtual Variant data( const ModelIndex& modelIndex, ModelRole role ) const { - if ( role == ModelRole::Display && modelIndex.column() == Columns::ID ) { - return Variant( String::format( "#%d (%s)", mThreads[modelIndex.row()].id, - mThreads[modelIndex.row()].name.c_str() ) ); - } else if ( role == ModelRole::Icon && modelIndex.column() == Columns::ID && - mThreads[modelIndex.row()].id == mCurrentThreadId ) { - static UIIcon* circleFilled = mSceneNode->findIcon( "circle-filled" ); - return Variant( circleFilled ); - } - return {}; - } - - void setThreads( std::vector&& threads ) { - { - Lock l( mResourceLock ); - mThreads = std::move( threads ); - } - invalidate(); - } - - void resetThreads() { - - { - Lock l( mResourceLock ); - mThreads = {}; - } - invalidate(); - } - - const DapThread& getThread( size_t index ) const { - Lock l( mResourceLock ); - eeASSERT( index < mThreads.size() ); - return mThreads[index]; - } - - ModelIndex fromThreadId( int id ) { - Lock l( mResourceLock ); - for ( size_t i = 0; i < mThreads.size(); i++ ) { - const DapThread& thread = mThreads[i]; - if ( thread.id == id ) - return index( i ); - } - return {}; - } - - void setCurrentThreadId( int id ) { - if ( mCurrentThreadId != id ) { - mCurrentThreadId = id; - invalidate( Model::UpdateFlag::DontInvalidateIndexes ); - } - } - - protected: - std::vector mThreads; - UISceneNode* mSceneNode{ nullptr }; - int mCurrentThreadId{ 1 }; -}; - -class StackModel : public Model { - public: - enum Columns { ID, Name, SourceName, SourcePath, Line, Column }; - - StackModel( StackTraceInfo&& stack, UISceneNode* sceneNode ) : - mStack( std::move( stack ) ), mSceneNode( sceneNode ) {} - - virtual size_t rowCount( const ModelIndex& ) const { - Lock l( mResourceLock ); - return mStack.stackFrames.size(); - } - - virtual size_t columnCount( const ModelIndex& ) const { return 5; } - - virtual std::string columnName( const size_t& colIdx ) const { - switch ( colIdx ) { - case Columns::ID: - return mSceneNode->i18n( "id", "ID" ); - case Columns::Name: - return mSceneNode->i18n( "name", "Name" ); - case Columns::SourceName: - return mSceneNode->i18n( "source_name", "Source Name" ); - case Columns::SourcePath: - return mSceneNode->i18n( "source_path", "Source Path" ); - case Columns::Line: - return mSceneNode->i18n( "line", "Line" ); - } - return ""; - } - - virtual Variant data( const ModelIndex& modelIndex, ModelRole role ) const { - Lock l( mResourceLock ); - if ( role == ModelRole::Display ) { - switch ( modelIndex.column() ) { - case Columns::ID: - return Variant( String::toString( mStack.stackFrames[modelIndex.row()].id ) ); - case Columns::Name: - return Variant( mStack.stackFrames[modelIndex.row()].name.c_str() ); - case Columns::SourceName: - return mStack.stackFrames[modelIndex.row()].source - ? Variant( mStack.stackFrames[modelIndex.row()].source->name ) - : Variant(); - case Columns::SourcePath: - return mStack.stackFrames[modelIndex.row()].source - ? Variant( mStack.stackFrames[modelIndex.row()].source->path ) - : Variant(); - case Columns::Line: - return Variant( String::toString( mStack.stackFrames[modelIndex.row()].line ) ); - case Columns::Column: - return Variant( - String::toString( mStack.stackFrames[modelIndex.row()].column ) ); - } - } else if ( role == ModelRole::Icon && modelIndex.column() == Columns::Name && - mCurrentScopeId == mStack.stackFrames[modelIndex.row()].id ) { - static UIIcon* circleFilled = mSceneNode->findIcon( "circle-filled" ); - return Variant( circleFilled ); - } - return {}; - } - - void setStack( StackTraceInfo&& stack ) { - { - Lock l( mResourceLock ); - mStack = std::move( stack ); - } - invalidate(); - } - - void resetStack() { - - { - Lock l( mResourceLock ); - mStack = {}; - } - invalidate(); - } - - const StackFrame& getStack( size_t index ) const { - Lock l( mResourceLock ); - eeASSERT( index < mStack.stackFrames.size() ); - return mStack.stackFrames[index]; - } - - void setCurrentScopeId( int scope ) { - if ( mCurrentScopeId != scope ) { - mCurrentScopeId = scope; - invalidate( Model::UpdateFlag::DontInvalidateIndexes ); - } - } - - protected: - StackTraceInfo mStack; - UISceneNode* mSceneNode{ nullptr }; - int mCurrentScopeId{ 0 }; -}; - DebuggerClientListener::DebuggerClientListener( DebuggerClient* client, DebuggerPlugin* plugin ) : mClient( client ), mPlugin( plugin ), - mVariablesRoot( std::make_shared( "Root", 0 ) ) { - ModelVariableNode::nodeMap[0] = mVariablesRoot; + mVariablesHolder( std::make_shared( plugin->getUISceneNode() ) ) { eeASSERT( mClient && mPlugin ); } @@ -399,10 +59,6 @@ void DebuggerClientListener::stateChanged( DebuggerClient::State state ) { mStackModel = std::make_shared( StackTraceInfo{}, sceneNode ); } - if ( !mVariablesModel ) { - mVariablesModel = std::make_shared( mVariablesRoot, sceneNode ); - } - UITableView* uiThreads = getStatusDebuggerController()->getUIThreads(); uiThreads->setModel( mThreadsModel ); @@ -426,7 +82,7 @@ void DebuggerClientListener::stateChanged( DebuggerClient::State state ) { } ); UITreeView* uiVariables = getStatusDebuggerController()->getUIVariables(); - uiVariables->setModel( mVariablesModel ); + uiVariables->setModel( mVariablesHolder->model ); uiVariables->removeEventsOfType( Event::OnModelEvent ); uiVariables->onModelEvent( [this]( const ModelEvent* modelEvent ) { if ( modelEvent->getModelEventType() == Abstract::ModelEventType::OpenTree ) { @@ -467,7 +123,7 @@ void DebuggerClientListener::resetState() { mThreadsModel->resetThreads(); if ( mStackModel ) mStackModel->resetStack(); - mVariablesRoot->clear(); + mVariablesHolder->clear(); } void DebuggerClientListener::debuggeeExited( int /*exitCode*/ ) { @@ -520,9 +176,12 @@ void DebuggerClientListener::outputProduced( const Output& output ) { void DebuggerClientListener::debuggingProcess( const ProcessInfo& ) {} -void DebuggerClientListener::errorResponse( const std::string& summary, +void DebuggerClientListener::errorResponse( const std::string& command, const std::string& summary, const std::optional& /*message*/ ) { - mPlugin->getPluginContext()->getNotificationCenter()->addNotification( summary, Seconds( 5 ) ); + if ( command != "evaluate" ) { + mPlugin->getPluginContext()->getNotificationCenter()->addNotification( summary, + Seconds( 5 ) ); + } } void DebuggerClientListener::threadChanged( const ThreadEvent& ) {} @@ -586,13 +245,11 @@ void DebuggerClientListener::scopes( const int /*frameId*/, std::vector&& if ( scopes.empty() ) return; - mVariablesRoot->clear(); + mVariablesHolder->clear(); for ( const auto& scope : scopes ) { auto child = std::make_shared( scope.name, scope.variablesReference ); - mVariablesRoot->addChild( child ); - ModelVariableNode::nodeMap[child->var.variablesReference] = child; - + mVariablesHolder->addChild( child ); mClient->variables( scope.variablesReference ); } @@ -610,40 +267,7 @@ void DebuggerClientListener::scopes( const int /*frameId*/, std::vector&& void DebuggerClientListener::variables( const int variablesReference, std::vector&& vars ) { - auto parentNode = ModelVariableNode::getNodeByReference( variablesReference ); - if ( !parentNode ) { - auto node = mVariablesRoot->getChildRecursive( variablesReference ); - if ( !node ) - return; - parentNode = *node; - } - - bool invalidateIndexes = false; - - for ( auto& var : vars ) { - if ( var.name.empty() ) - continue; - - auto found = parentNode->getChild( var.name ); - if ( found ) { - ( *found )->var = std::move( var ); - - if ( ( *found )->var.variablesReference != 0 ) - ModelVariableNode::nodeMap[( *found )->var.variablesReference] = *found; - continue; - } - - invalidateIndexes = true; - - auto child = std::make_shared( std::move( var ), parentNode ); - parentNode->addChild( child ); - - if ( child->var.variablesReference != 0 ) - ModelVariableNode::nodeMap[child->var.variablesReference] = child; - } - - mVariablesModel->invalidate( invalidateIndexes ? Model::UpdateFlag::InvalidateAllIndexes - : Model::UpdateFlag::DontInvalidateIndexes ); + mVariablesHolder->addVariables( variablesReference, std::move( vars ) ); } void DebuggerClientListener::modules( ModulesInfo&& ) {} diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp index c926472a9..061f4f573 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp @@ -8,6 +8,7 @@ class DebuggerPlugin; class ThreadsModel; class StackModel; class VariablesModel; +class VariablesHolder; struct ModelVariableNode; class DebuggerClientListener : public DebuggerClient::Listener { @@ -33,7 +34,8 @@ class DebuggerClientListener : public DebuggerClient::Listener { void debuggeeContinued( const ContinuedEvent& ); void outputProduced( const Output& ); void debuggingProcess( const ProcessInfo& ); - void errorResponse( const std::string& summary, const std::optional& message ); + void errorResponse( const std::string& command, const std::string& summary, + const std::optional& message ); void threadChanged( const ThreadEvent& ); void moduleChanged( const ModuleEvent& ); void threads( std::vector&& ); @@ -73,8 +75,7 @@ class DebuggerClientListener : public DebuggerClient::Listener { int mCurrentFrameId{ 0 }; std::shared_ptr mThreadsModel; std::shared_ptr mStackModel; - std::shared_ptr mVariablesModel; - std::shared_ptr mVariablesRoot; + std::shared_ptr mVariablesHolder; StatusDebuggerController* getStatusDebuggerController() const; diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index 80684e865..36984094b 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -80,6 +80,7 @@ class DebuggerPlugin : public PluginBase { Mutex mDapsMutex; Mutex mBreakpointsMutex; StatusDebuggerController::State mDebuggingState{ StatusDebuggerController::State::NotStarted }; + std::vector mExpressions; // Begin Hover Stuff Uint32 mHoverWaitCb{ 0 }; diff --git a/src/tools/ecode/plugins/debugger/models/stackmodel.cpp b/src/tools/ecode/plugins/debugger/models/stackmodel.cpp new file mode 100644 index 000000000..4881f3b3c --- /dev/null +++ b/src/tools/ecode/plugins/debugger/models/stackmodel.cpp @@ -0,0 +1,93 @@ +#include "stackmodel.hpp" +#include + +namespace ecode { + +StackModel::StackModel( StackTraceInfo&& stack, UISceneNode* sceneNode ) : + mStack( std::move( stack ) ), mSceneNode( sceneNode ) {} + +size_t StackModel::rowCount( const ModelIndex& ) const { + Lock l( mResourceLock ); + return mStack.stackFrames.size(); +} + +size_t StackModel::columnCount( const ModelIndex& ) const { + return 5; +} + +std::string StackModel::columnName( const size_t& colIdx ) const { + switch ( colIdx ) { + case Columns::ID: + return mSceneNode->i18n( "id", "ID" ); + case Columns::Name: + return mSceneNode->i18n( "name", "Name" ); + case Columns::SourceName: + return mSceneNode->i18n( "source_name", "Source Name" ); + case Columns::SourcePath: + return mSceneNode->i18n( "source_path", "Source Path" ); + case Columns::Line: + return mSceneNode->i18n( "line", "Line" ); + } + return ""; +} + +Variant StackModel::data( const ModelIndex& modelIndex, ModelRole role ) const { + Lock l( mResourceLock ); + if ( role == ModelRole::Display ) { + switch ( modelIndex.column() ) { + case Columns::ID: + return Variant( String::toString( mStack.stackFrames[modelIndex.row()].id ) ); + case Columns::Name: + return Variant( mStack.stackFrames[modelIndex.row()].name.c_str() ); + case Columns::SourceName: + return mStack.stackFrames[modelIndex.row()].source + ? Variant( mStack.stackFrames[modelIndex.row()].source->name ) + : Variant(); + case Columns::SourcePath: + return mStack.stackFrames[modelIndex.row()].source + ? Variant( mStack.stackFrames[modelIndex.row()].source->path ) + : Variant(); + case Columns::Line: + return Variant( String::toString( mStack.stackFrames[modelIndex.row()].line ) ); + case Columns::Column: + return Variant( String::toString( mStack.stackFrames[modelIndex.row()].column ) ); + } + } else if ( role == ModelRole::Icon && modelIndex.column() == Columns::Name && + mCurrentScopeId == mStack.stackFrames[modelIndex.row()].id ) { + static UIIcon* circleFilled = mSceneNode->findIcon( "circle-filled" ); + return Variant( circleFilled ); + } + return {}; +} + +void StackModel::setStack( StackTraceInfo&& stack ) { + { + Lock l( mResourceLock ); + mStack = std::move( stack ); + } + invalidate(); +} + +void StackModel::resetStack() { + + { + Lock l( mResourceLock ); + mStack = {}; + } + invalidate(); +} + +const StackFrame& StackModel::getStack( size_t index ) const { + Lock l( mResourceLock ); + eeASSERT( index < mStack.stackFrames.size() ); + return mStack.stackFrames[index]; +} + +void StackModel::setCurrentScopeId( int scope ) { + if ( mCurrentScopeId != scope ) { + mCurrentScopeId = scope; + invalidate( Model::UpdateFlag::DontInvalidateIndexes ); + } +} + +} // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/models/stackmodel.hpp b/src/tools/ecode/plugins/debugger/models/stackmodel.hpp new file mode 100644 index 000000000..e8f98246f --- /dev/null +++ b/src/tools/ecode/plugins/debugger/models/stackmodel.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "../dap/protocol.hpp" +#include + +using namespace EE; +using namespace EE::UI; +using namespace EE::UI::Models; + +namespace EE::UI { +class UISceneNode; +} + +namespace ecode { + +using namespace dap; + +class StackModel : public Model { + public: + enum Columns { ID, Name, SourceName, SourcePath, Line, Column }; + + StackModel( StackTraceInfo&& stack, UISceneNode* sceneNode ); + + virtual size_t rowCount( const ModelIndex& ) const; + + virtual size_t columnCount( const ModelIndex& ) const; + + virtual std::string columnName( const size_t& colIdx ) const; + + virtual Variant data( const ModelIndex& modelIndex, ModelRole role ) const; + + void setStack( StackTraceInfo&& stack ); + + void resetStack(); + + const StackFrame& getStack( size_t index ) const; + + void setCurrentScopeId( int scope ); + + protected: + StackTraceInfo mStack; + UISceneNode* mSceneNode{ nullptr }; + int mCurrentScopeId{ 0 }; +}; + +} // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/models/threadsmodel.cpp b/src/tools/ecode/plugins/debugger/models/threadsmodel.cpp new file mode 100644 index 000000000..5c9776b3e --- /dev/null +++ b/src/tools/ecode/plugins/debugger/models/threadsmodel.cpp @@ -0,0 +1,77 @@ +#include "threadsmodel.hpp" +#include + +namespace ecode { + +ThreadsModel::ThreadsModel( const std::vector& threads, UISceneNode* sceneNode ) : + mThreads( threads ), mSceneNode( sceneNode ) {} + +size_t ThreadsModel::rowCount( const ModelIndex& ) const { + return mThreads.size(); +} + +size_t ThreadsModel::columnCount( const ModelIndex& ) const { + return 1; +} + +std::string ThreadsModel::columnName( const size_t& colIdx ) const { + switch ( colIdx ) { + case Columns::ID: + return mSceneNode->i18n( "thread_id", "Thread ID" ); + } + return ""; +} + +Variant ThreadsModel::data( const ModelIndex& modelIndex, ModelRole role ) const { + if ( role == ModelRole::Display && modelIndex.column() == Columns::ID ) { + return Variant( String::format( "#%d (%s)", mThreads[modelIndex.row()].id, + mThreads[modelIndex.row()].name.c_str() ) ); + } else if ( role == ModelRole::Icon && modelIndex.column() == Columns::ID && + mThreads[modelIndex.row()].id == mCurrentThreadId ) { + static UIIcon* circleFilled = mSceneNode->findIcon( "circle-filled" ); + return Variant( circleFilled ); + } + return {}; +} + +void ThreadsModel::setThreads( std::vector&& threads ) { + { + Lock l( mResourceLock ); + mThreads = std::move( threads ); + } + invalidate(); +} + +void ThreadsModel::resetThreads() { + + { + Lock l( mResourceLock ); + mThreads = {}; + } + invalidate(); +} + +const DapThread& ThreadsModel::getThread( size_t index ) const { + Lock l( mResourceLock ); + eeASSERT( index < mThreads.size() ); + return mThreads[index]; +} + +ModelIndex ThreadsModel::fromThreadId( int id ) { + Lock l( mResourceLock ); + for ( size_t i = 0; i < mThreads.size(); i++ ) { + const DapThread& thread = mThreads[i]; + if ( thread.id == id ) + return index( i ); + } + return {}; +} + +void ThreadsModel::setCurrentThreadId( int id ) { + if ( mCurrentThreadId != id ) { + mCurrentThreadId = id; + invalidate( Model::UpdateFlag::DontInvalidateIndexes ); + } +} + +} // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/models/threadsmodel.hpp b/src/tools/ecode/plugins/debugger/models/threadsmodel.hpp new file mode 100644 index 000000000..b670cd88d --- /dev/null +++ b/src/tools/ecode/plugins/debugger/models/threadsmodel.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "../dap/protocol.hpp" +#include + +using namespace EE; +using namespace EE::UI; +using namespace EE::UI::Models; + +namespace EE::UI { +class UISceneNode; +} + +namespace ecode { + +using namespace dap; + +class ThreadsModel : public Model { + public: + enum Columns { ID }; + + ThreadsModel( const std::vector& threads, UISceneNode* sceneNode ); + + virtual size_t rowCount( const ModelIndex& ) const; + + virtual size_t columnCount( const ModelIndex& ) const; + + virtual std::string columnName( const size_t& colIdx ) const; + + virtual Variant data( const ModelIndex& modelIndex, ModelRole role ) const; + + void setThreads( std::vector&& threads ); + + void resetThreads(); + + const DapThread& getThread( size_t index ) const; + + ModelIndex fromThreadId( int id ); + + void setCurrentThreadId( int id ); + + protected: + std::vector mThreads; + UISceneNode* mSceneNode{ nullptr }; + int mCurrentThreadId{ 1 }; +}; + +} // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp new file mode 100644 index 000000000..76d8dc97b --- /dev/null +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp @@ -0,0 +1,219 @@ +#include "variablesmodel.hpp" +#include + +namespace ecode { + +ModelVariableNode::ModelVariableNode( Variable&& var, NodePtr parent ) : + parent( parent ), var( std::move( var ) ) {} + +ModelVariableNode::ModelVariableNode( const std::string& name, int variablesReference, + NodePtr parent ) : + parent( parent ) { + var.name = name; + var.variablesReference = variablesReference; +} + +ModelVariableNode::~ModelVariableNode() {} + +const std::string& ModelVariableNode::getName() const { + return var.name; +} + +int ModelVariableNode::getVariablesReference() const { + return var.variablesReference; +} + +std::optional +ModelVariableNode::getChildRecursive( int variablesReference ) { + if ( var.variablesReference == variablesReference ) + return shared_from_this(); + + for ( const auto& child : children ) { + auto found = child->getChild( variablesReference ); + if ( found ) + return found; + } + return {}; +} + +void ModelVariableNode::clear() { + children.clear(); +} + +void ModelVariableNode::addChild( NodePtr child ) { + children.emplace_back( child ); +} + +ModelVariableNode::NodePtr ModelVariableNode::getParent() const { + return parent; +} + +std::optional ModelVariableNode::getChild( int variablesReference ) { + auto found = std::find_if( children.begin(), children.end(), + [variablesReference]( const NodePtr& child ) { + return child->var.variablesReference == variablesReference; + } ); + return ( found != children.end() ) ? *found : std::optional{}; +} + +std::optional ModelVariableNode::getChild( const std::string& name ) { + auto found = std::find_if( children.begin(), children.end(), [&name]( const NodePtr& child ) { + return child->var.name == name; + } ); + return ( found != children.end() ) ? *found : std::optional{}; +} + +const std::vector& ModelVariableNode::getChildren() const { + return children; +} + +VariablesModel::VariablesModel( ModelVariableNode::NodePtr rootNode, UISceneNode* sceneNode ) : + rootNode( rootNode ), mSceneNode( sceneNode ) {} + +ModelIndex VariablesModel::index( int row, int column, const ModelIndex& parent ) const { + ModelVariableNode* parentNode = parent.isValid() + ? static_cast( parent.internalData() ) + : rootNode.get(); + + if ( row >= 0 && row < static_cast( parentNode->getChildren().size() ) ) { + ModelVariableNode::NodePtr childNode = parentNode->getChildren()[row]; + return createIndex( row, column, childNode.get() ); + } + + return ModelIndex(); +} + +ModelIndex VariablesModel::parentIndex( const ModelIndex& index ) const { + if ( !index.isValid() ) + return ModelIndex(); + + ModelVariableNode* childNode = static_cast( index.internalData() ); + ModelVariableNode::NodePtr parentNode = childNode->getParent(); + + if ( parentNode == nullptr || parentNode == rootNode ) + return ModelIndex(); + + ModelVariableNode::NodePtr grandParentNode = parentNode->getParent(); + if ( grandParentNode == nullptr ) + grandParentNode = rootNode; + + int row = std::distance( grandParentNode->getChildren().begin(), + std::find_if( grandParentNode->getChildren().begin(), + grandParentNode->getChildren().end(), + [parentNode]( ModelVariableNode::NodePtr node ) { + return node.get() == parentNode.get(); + } ) ); + + return createIndex( row, Columns::Name, parentNode.get() ); +} + +size_t VariablesModel::rowCount( const ModelIndex& index ) const { + ModelVariableNode* parentNode = + index.isValid() ? static_cast( index.internalData() ) : rootNode.get(); + + return static_cast( parentNode->getChildren().size() ); +} + +bool VariablesModel::hasChilds( const ModelIndex& index ) const { + if ( !index.isValid() ) + return !rootNode->children.empty(); + ModelVariableNode* node = static_cast( index.internalData() ); + return !node->children.empty() || node->var.variablesReference > 0; +} + +size_t VariablesModel::columnCount( const ModelIndex& ) const { + return 3; +} + +std::string VariablesModel::columnName( const size_t& colIdx ) const { + switch ( colIdx ) { + case Columns::Name: + return mSceneNode->i18n( "variable_name", "Variable Name" ); + case Columns::Value: + return mSceneNode->i18n( "value", "Value" ); + case Columns::Type: + return mSceneNode->i18n( "type", "Type" ); + } + return ""; +} + +Variant VariablesModel::data( const ModelIndex& index, ModelRole role ) const { + static const char* EMPTY = ""; + if ( !index.isValid() ) + return EMPTY; + + ModelVariableNode* node = static_cast( index.internalData() ); + + if ( role == ModelRole::Display ) { + switch ( index.column() ) { + case 0: + return Variant( node->var.name.c_str() ); + case 1: + return Variant( node->var.value.c_str() ); + case 2: + return Variant( node->var.type ? node->var.type->c_str() : EMPTY ); + } + } + + return EMPTY; +} + +VariablesHolder::VariablesHolder( UISceneNode* sceneNode ) : + rootNode( std::make_shared( "Root", 0 ) ), + model( std::make_shared( rootNode, sceneNode ) ) { + nodeMap[0] = rootNode; +} + +void VariablesHolder::addVariables( const int variablesReference, std::vector&& vars ) { + auto parentNode = getNodeByReference( variablesReference ); + if ( !parentNode ) { + auto node = rootNode->getChildRecursive( variablesReference ); + if ( !node ) + return; + parentNode = *node; + } + + bool invalidateIndexes = false; + + for ( auto& var : vars ) { + if ( var.name.empty() ) + continue; + + auto found = parentNode->getChild( var.name ); + if ( found ) { + ( *found )->var = std::move( var ); + + if ( ( *found )->var.variablesReference != 0 ) + nodeMap[( *found )->var.variablesReference] = *found; + continue; + } + + invalidateIndexes = true; + + auto child = std::make_shared( std::move( var ), parentNode ); + parentNode->addChild( child ); + + if ( child->var.variablesReference != 0 ) + nodeMap[child->var.variablesReference] = child; + } + + model->invalidate( invalidateIndexes ? Model::UpdateFlag::InvalidateAllIndexes + : Model::UpdateFlag::DontInvalidateIndexes ); +} + +void VariablesHolder::addChild( ModelVariableNode::NodePtr child ) { + rootNode->addChild( child ); + nodeMap[child->var.variablesReference] = child; +} + +void VariablesHolder::clear() { + rootNode->clear(); + // modelMap.clear(); +} + +ModelVariableNode::NodePtr VariablesHolder::getNodeByReference( int variablesReference ) { + auto it = nodeMap.find( variablesReference ); + return ( it != nodeMap.end() ) ? it->second : nullptr; +} + +} // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp new file mode 100644 index 000000000..899a3342c --- /dev/null +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include "../dap/protocol.hpp" +#include + +using namespace EE; +using namespace EE::UI; +using namespace EE::UI::Models; + +namespace EE::UI { +class UISceneNode; +} + +namespace ecode { + +using namespace dap; + +struct ModelVariableNode : public std::enable_shared_from_this { + using NodePtr = std::shared_ptr; + + ModelVariableNode( Variable&& var, NodePtr parent ); + + ModelVariableNode( const std::string& name, int variablesReference, NodePtr parent = nullptr ); + + virtual ~ModelVariableNode(); + + const std::vector& getChildren() const; + + const std::string& getName() const; + + int getVariablesReference() const; + + void clear(); + + std::optional getChildRecursive( int variablesReference ); + + std::optional getChild( const std::string& name ); + + std::optional getChild( int variablesReference ); + + void addChild( NodePtr child ); + + NodePtr getParent() const; + + NodePtr parent{ nullptr }; + Variable var; + std::vector children; +}; + +class VariablesModel : public Model { + public: + enum Columns { Name, Value, Type }; + + VariablesModel( ModelVariableNode::NodePtr rootNode, UISceneNode* sceneNode ); + + ModelIndex index( int row, int column, const ModelIndex& parent = ModelIndex() ) const override; + + ModelIndex parentIndex( const ModelIndex& index ) const override; + + size_t rowCount( const ModelIndex& index = ModelIndex() ) const override; + + bool hasChilds( const ModelIndex& index = ModelIndex() ) const override; + + size_t columnCount( const ModelIndex& ) const override; + + std::string columnName( const size_t& colIdx ) const override; + + Variant data( const ModelIndex& index, ModelRole role ) const override; + + protected: + ModelVariableNode::NodePtr rootNode; + UISceneNode* mSceneNode; +}; + +struct VariablesHolder { + VariablesHolder( UISceneNode* sceneNode ); + + void addVariables( const int variablesReference, std::vector&& vars ); + + void addChild( ModelVariableNode::NodePtr child ); + + void clear(); + + ModelVariableNode::NodePtr getNodeByReference( int variablesReference ); + + std::shared_ptr rootNode; + std::shared_ptr model; + std::unordered_map nodeMap; +}; + +} // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp index 133ec2ccd..ce943b139 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp @@ -134,10 +134,12 @@ void StatusDebuggerController::createContainer() { - + + + @@ -169,6 +171,7 @@ void StatusDebuggerController::createContainer() { mContainer->bind( "debugger_stack", mUIStack ); mContainer->bind( "debugger_breakpoints", mUIBreakpoints ); mContainer->bind( "debugger_variables", mUIVariables ); + mContainer->bind( "debugger_expressions", mUIExpressions ); mContainer->bind( "app_debugger_start", mUIButStart ); mContainer->bind( "app_debugger_stop", mUIButStop ); mContainer->bind( "app_debugger_pause", mUIButPause ); @@ -208,6 +211,9 @@ void StatusDebuggerController::createContainer() { mUIBreakpoints->setAutoColumnsWidth( true ); mUIBreakpoints->setFitAllColumnsToWidget( true ); mUIBreakpoints->setMainColumn( 1 ); + + mUIExpressions->setAutoColumnsWidth( true ); + mUIExpressions->setFitAllColumnsToWidget( true ); } } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp index 2763f416b..b766eb348 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp @@ -66,6 +66,7 @@ class StatusDebuggerController : public StatusBarElement { UITableView* mUIStack{ nullptr }; UIBreakpointsTableView* mUIBreakpoints{ nullptr }; UITreeView* mUIVariables{ nullptr }; + UITreeView* mUIExpressions{ nullptr }; UISplitter* mUIThreadsSplitter{ nullptr }; UIPushButton* mUIButStart{ nullptr }; UIPushButton* mUIButStop{ nullptr };