diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 54a63dd7e..82a19874b 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -1588,6 +1588,8 @@ ../../src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp ../../src/tools/ecode/plugins/debugger/debuggerplugin.cpp ../../src/tools/ecode/plugins/debugger/debuggerplugin.hpp +../../src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp +../../src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp ../../src/tools/ecode/plugins/formatter/formatterplugin.cpp ../../src/tools/ecode/plugins/formatter/formatterplugin.hpp ../../src/tools/ecode/notificationcenter.cpp diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 4efb83fe1..213a6c7f5 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -577,7 +577,10 @@ void App::initPluginManager() { } ); } }; + +#ifdef EE_DEBUG mPluginManager->registerPlugin( DebuggerPlugin::Definition() ); +#endif mPluginManager->registerPlugin( LinterPlugin::Definition() ); mPluginManager->registerPlugin( FormatterPlugin::Definition() ); mPluginManager->registerPlugin( AutoCompletePlugin::Definition() ); diff --git a/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.cpp b/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.cpp index 72ea49475..49178c04e 100644 --- a/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.cpp +++ b/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.cpp @@ -611,13 +611,13 @@ bool DebuggerClientDap::evaluate( const std::string& expression, const std::stri } bool DebuggerClientDap::setBreakpoints( const std::string& path, - const std::vector breakpoints, + const std::vector& breakpoints, bool sourceModified ) { return setBreakpoints( Source( path ), breakpoints, sourceModified ); } bool DebuggerClientDap::setBreakpoints( const dap::Source& source, - const std::vector breakpoints, + const std::vector& breakpoints, bool sourceModified ) { nlohmann::json bpoints = nlohmann::json::array(); for ( const auto& item : breakpoints ) diff --git a/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.hpp b/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.hpp index 76a2ac59b..40c911f83 100644 --- a/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.hpp +++ b/src/tools/ecode/plugins/debugger/dap/debuggerclientdap.hpp @@ -57,11 +57,11 @@ class DebuggerClientDap : public DebuggerClient { bool supportsTerminate() const override; bool setBreakpoints( const std::string& path, - const std::vector breakpoints, + const std::vector& breakpoints, bool sourceModified = false ) override; bool setBreakpoints( const dap::Source& source, - const std::vector breakpoints, + const std::vector& breakpoints, bool sourceModified = false ) override; bool gotoTargets( const std::string& path, const int line, diff --git a/src/tools/ecode/plugins/debugger/dap/protocol.hpp b/src/tools/ecode/plugins/debugger/dap/protocol.hpp index cec3faf65..a8606643e 100644 --- a/src/tools/ecode/plugins/debugger/dap/protocol.hpp +++ b/src/tools/ecode/plugins/debugger/dap/protocol.hpp @@ -173,6 +173,16 @@ struct SourceBreakpoint { bool operator==( const SourceBreakpoint& other ) const { return line == other.line; } }; +struct SourceBreakpointStateful : public SourceBreakpoint { + bool enabled{ true }; + + SourceBreakpointStateful() = default; + SourceBreakpointStateful( const json& body ) : SourceBreakpoint( body ) {} + SourceBreakpointStateful( const int line ) : SourceBreakpoint( line ) {} + + bool operator==( const SourceBreakpointStateful& other ) const { return line == other.line; } +}; + struct Breakpoint { /** * An optional identifier for the breakpoint. It is needed if breakpoint @@ -489,3 +499,16 @@ template <> struct std::hash { return hashCombine( h1, h2, h3, h4, h5 ); } }; + +template <> struct std::hash { + std::size_t operator()( ecode::dap::SourceBreakpointStateful const& breakpoint ) const noexcept { + size_t h1 = std::hash()( breakpoint.line ); + size_t h2 = breakpoint.column ? std::hash()( *breakpoint.column ) : 0; + size_t h3 = breakpoint.condition ? std::hash()( *breakpoint.condition ) : 0; + size_t h4 = + breakpoint.hitCondition ? std::hash()( *breakpoint.hitCondition ) : 0; + size_t h5 = breakpoint.logMessage ? std::hash()( *breakpoint.logMessage ) : 0; + size_t h6 = std::hash()( breakpoint.enabled ); + return hashCombine( h1, h2, h3, h4, h5, h6 ); + } +}; diff --git a/src/tools/ecode/plugins/debugger/debuggerclient.hpp b/src/tools/ecode/plugins/debugger/debuggerclient.hpp index 3c5d69e88..ddb4bf5d0 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclient.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerclient.hpp @@ -89,11 +89,11 @@ class DebuggerClient { virtual bool supportsTerminate() const = 0; virtual bool setBreakpoints( const std::string& path, - const std::vector breakpoints, + const std::vector& breakpoints, bool sourceModified = false ) = 0; virtual bool setBreakpoints( const dap::Source& source, - const std::vector breakpoints, + const std::vector& breakpoints, bool sourceModified = false ) = 0; virtual bool gotoTargets( const std::string& path, const int line, diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index 804620607..dda343f09 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -4,6 +4,15 @@ namespace ecode { +static std::vector fromSet( const UnorderedSet& set ) { + std::vector bps; + bps.reserve( set.size() ); + for ( const auto& bp : set ) + if ( bp.enabled ) + bps.emplace_back( bp ); + return bps; +} + DebuggerClientListener::DebuggerClientListener( DebuggerClient* client, DebuggerPlugin* plugin ) : mClient( client ), mPlugin( plugin ) { eeASSERT( mClient && mPlugin ); @@ -12,6 +21,8 @@ DebuggerClientListener::DebuggerClientListener( DebuggerClient* client, Debugger void DebuggerClientListener::stateChanged( DebuggerClient::State state ) { if ( state == DebuggerClient::State::Initializing ) { mPlugin->getManager()->getUISceneNode()->runOnMainThread( [this] { + getStatusDebuggerController()->createWidget(); + mPlugin->getManager() ->getPluginContext() ->getStatusAppOutputController() @@ -21,8 +32,9 @@ void DebuggerClientListener::stateChanged( DebuggerClient::State state ) { } void DebuggerClientListener::initialized() { - // mClient->setBreakpoints( "/home/programming/eepp/src/tools/ecode/ecode.cpp", - // { SourceBreakpoint( 4116 ) } ); + Lock l( mPlugin->mBreakpointsMutex ); + for ( const auto& fileBps : mPlugin->mBreakpoints ) + mClient->setBreakpoints( fileBps.first, fromSet( fileBps.second ) ); } void DebuggerClientListener::launched() {} @@ -42,10 +54,10 @@ void DebuggerClientListener::debuggeeExited( int /*exitCode*/ ) { } void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) { - Log::warning( "DebuggerClientListener::debuggeeStopped: reason %s", event.reason ); - // if ( event.threadId ) { - // mClient->stackTrace( *event.threadId ); - // } + Log::debug( "DebuggerClientListener::debuggeeStopped: reason %s", event.reason ); + mClient->threads(); + if ( event.threadId ) + mClient->stackTrace( *event.threadId ); } void DebuggerClientListener::debuggeeContinued( const ContinuedEvent& ) {} @@ -67,12 +79,93 @@ void DebuggerClientListener::threadChanged( const ThreadEvent& ) {} void DebuggerClientListener::moduleChanged( const ModuleEvent& ) {} -void DebuggerClientListener::threads( const std::vector& /*threads*/ ) {} +class ThreadsModel : public Model { + public: + ThreadsModel( const std::vector& threads ) : mThreads( threads ) {} + virtual size_t rowCount( const ModelIndex& ) const { return mThreads.size(); } + virtual size_t columnCount( const ModelIndex& ) const { return 2; } + + virtual std::string columnName( const size_t& colIdx ) const { + return colIdx == 0 ? "ID" : "Name"; + } + + virtual Variant data( const ModelIndex& modelIndex, ModelRole role ) const { + if ( role == ModelRole::Display ) { + return modelIndex.column() == 0 + ? Variant( String::toString( mThreads[modelIndex.row()].id ) ) + : Variant( mThreads[modelIndex.row()].name.c_str() ); + } + return {}; + } + + protected: + std::vector mThreads; +}; + +void DebuggerClientListener::threads( const std::vector& threads ) { + getStatusDebuggerController()->getUIThreads()->setModel( + std::make_shared( threads ) ); +} + +class StackModel : public Model { + public: + StackModel( const StackTraceInfo& stack ) : mStack( stack ) {} + virtual size_t rowCount( const ModelIndex& ) const { 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 0: + return "ID"; + case 1: + return "Name"; + case 2: + return "Source Name"; + case 3: + return "Source Path"; + case 4: + return "Line"; + case 5: + return "Column"; + } + return ""; + } + + virtual Variant data( const ModelIndex& modelIndex, ModelRole role ) const { + if ( role == ModelRole::Display ) { + switch ( modelIndex.column() ) { + case 0: + return Variant( String::toString( mStack.stackFrames[modelIndex.row()].id ) ); + case 1: + return Variant( mStack.stackFrames[modelIndex.row()].name.c_str() ); + case 2: + return mStack.stackFrames[modelIndex.row()].source + ? Variant( mStack.stackFrames[modelIndex.row()].source->name ) + : Variant(); + case 3: + return mStack.stackFrames[modelIndex.row()].source + ? Variant( mStack.stackFrames[modelIndex.row()].source->path ) + : Variant(); + case 4: + return Variant( String::toString( mStack.stackFrames[modelIndex.row()].line ) ); + case 5: + return Variant( + String::toString( mStack.stackFrames[modelIndex.row()].column ) ); + } + } + return {}; + } + + protected: + StackTraceInfo mStack; +}; void DebuggerClientListener::stackTrace( const int /*threadId*/, const StackTraceInfo& stack ) { - // if ( !stack.stackFrames.empty() ) { - // mClient->scopes( stack.stackFrames[0].id ); - // } + getStatusDebuggerController()->getUIStack()->setModel( std::make_shared( stack ) ); + + if ( !stack.stackFrames.empty() ) { + mClient->scopes( stack.stackFrames[0].id ); + } } void DebuggerClientListener::scopes( const int /*frameId**/, const std::vector& scopes ) { @@ -106,4 +199,15 @@ void DebuggerClientListener::expressionEvaluated( const std::string& /*expressio void DebuggerClientListener::gotoTargets( const Source& /*source*/, const int /*line*/, const std::vector& /*targets*/ ) {} +StatusDebuggerController* DebuggerClientListener::getStatusDebuggerController() const { + + auto debuggerElement = + mPlugin->getManager()->getPluginContext()->getStatusBar()->getStatusBarElement( + "status_app_debugger" ); + + if ( !debuggerElement ) + return nullptr; + return static_cast( debuggerElement.get() ); +} + } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp index afcbf023a..8d7f80c2e 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp @@ -1,5 +1,6 @@ #pragma once #include "debuggerclient.hpp" +#include "statusdebuggercontroller.hpp" namespace ecode { @@ -44,6 +45,8 @@ class DebuggerClientListener : public DebuggerClient::Listener { protected: DebuggerClient* mClient{ nullptr }; DebuggerPlugin* mPlugin{ nullptr }; + + StatusDebuggerController* getStatusDebuggerController() const; }; } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index ed2880d32..ffc3032e1 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -450,11 +450,11 @@ bool DebuggerPlugin::onLineNumberClick( UICodeEditor* editor, Uint32 lineNumber return false; Lock l( mBreakpointsMutex ); auto& breakpoints = mBreakpoints[editor->getDocument().getFilePath()]; - auto breakpointIt = breakpoints.find( SourceBreakpoint( lineNumber ) ); + auto breakpointIt = breakpoints.find( SourceBreakpointStateful( lineNumber ) ); if ( breakpointIt != breakpoints.end() ) { breakpoints.erase( breakpointIt ); } else { - breakpoints.insert( SourceBreakpoint( lineNumber ) ); + breakpoints.insert( SourceBreakpointStateful( lineNumber ) ); } editor->invalidateDraw(); return true; diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index 0776954ef..cc1d133ae 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -64,7 +64,7 @@ class DebuggerPlugin : public PluginBase { UIDropDownList* mUIDebuggerList{ nullptr }; UIDropDownList* mUIDebuggerConfList{ nullptr }; UIPushButton* mRunButton{ nullptr }; - UnorderedMap> mBreakpoints; + UnorderedMap> mBreakpoints; Mutex mBreakpointsMutex; DebuggerPlugin( PluginManager* pluginManager, bool sync ); diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp index e6737c2b5..d9f1f88fe 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp @@ -18,12 +18,30 @@ UIWidget* StatusDebuggerController::createWidget() { return mContainer; } +UITableView* StatusDebuggerController::getUIThreads() { + return mUIThreads; +} + +UITableView* StatusDebuggerController::getUIStack() { + return mUIStack; +} + +UITableView* StatusDebuggerController::getUIBreakpoints() { + return mUIBreakpoints; +} + void StatusDebuggerController::createContainer() { if ( mContainer ) return; const auto XML = R"xml( - - + + + + + + + + )xml"; if ( mMainSplitter->getLastWidget() != nullptr ) { @@ -34,6 +52,10 @@ void StatusDebuggerController::createContainer() { mContainer = mContext->getUISceneNode() ->loadLayoutFromString( XML, mMainSplitter ) ->asType(); + + mContainer->bind( "debugger_threads", mUIThreads ); + mContainer->bind( "debugger_stack", mUIStack ); + mContainer->bind( "debugger_breakpoints", mUIBreakpoints ); } } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp index 2a7252a7c..09d434c45 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp @@ -27,8 +27,17 @@ class StatusDebuggerController : public StatusBarElement { UIWidget* createWidget(); + UITableView* getUIThreads(); + + UITableView* getUIStack(); + + UITableView* getUIBreakpoints(); + protected: UILinearLayout* mContainer{ nullptr }; + UITableView* mUIThreads{ nullptr }; + UITableView* mUIStack{ nullptr }; + UITableView* mUIBreakpoints{ nullptr }; void createContainer(); }; diff --git a/src/tools/ecode/uistatusbar.cpp b/src/tools/ecode/uistatusbar.cpp index c05e39bab..062a7ddf6 100644 --- a/src/tools/ecode/uistatusbar.cpp +++ b/src/tools/ecode/uistatusbar.cpp @@ -1,9 +1,9 @@ +#include "uistatusbar.hpp" #include "globalsearchcontroller.hpp" #include "plugins/plugincontextprovider.hpp" #include "statusappoutputcontroller.hpp" #include "statusbuildoutputcontroller.hpp" #include "statusterminalcontroller.hpp" -#include "uistatusbar.hpp" #include "universallocator.hpp" #include #include @@ -160,6 +160,13 @@ void UIStatusBar::setPluginContextProvider( PluginContextProvider* app ) { updateState(); } +std::shared_ptr UIStatusBar::getStatusBarElement( const std::string& id ) const { + auto elemIt = mElements.find( id ); + if ( elemIt != mElements.end() ) + return elemIt->second.second; + return {}; +} + void UIStatusBar::onVisibilityChange() { UILinearLayout::onVisibilityChange(); if ( isVisible() ) diff --git a/src/tools/ecode/uistatusbar.hpp b/src/tools/ecode/uistatusbar.hpp index 7ba9ef89a..7b03b322a 100644 --- a/src/tools/ecode/uistatusbar.hpp +++ b/src/tools/ecode/uistatusbar.hpp @@ -51,6 +51,8 @@ class UIStatusBar : public UILinearLayout, public WidgetCommandExecuter { void setPluginContextProvider( PluginContextProvider* app ); + std::shared_ptr getStatusBarElement( const std::string& id ) const; + protected: UnorderedMap>> mElements;