From c4bd88461dadef6c623ae0e7e2d832e40d141e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 3 Jan 2025 22:01:16 -0300 Subject: [PATCH] Still more WIP --- .../ecode/plugins/debugger/dap/protocol.hpp | 3 +- .../debugger/debuggerclientlistener.cpp | 208 +++++++++++------- .../debugger/debuggerclientlistener.hpp | 18 ++ .../ecode/plugins/debugger/debuggerplugin.cpp | 65 +++++- .../ecode/plugins/debugger/debuggerplugin.hpp | 10 +- .../debugger/statusdebuggercontroller.cpp | 14 ++ src/tools/ecode/plugins/git/gitplugin.cpp | 10 - src/tools/ecode/plugins/git/gitplugin.hpp | 4 - src/tools/ecode/plugins/plugin.cpp | 17 ++ src/tools/ecode/plugins/plugin.hpp | 15 +- 10 files changed, 251 insertions(+), 113 deletions(-) diff --git a/src/tools/ecode/plugins/debugger/dap/protocol.hpp b/src/tools/ecode/plugins/debugger/dap/protocol.hpp index a8606643e..6e63bbf4e 100644 --- a/src/tools/ecode/plugins/debugger/dap/protocol.hpp +++ b/src/tools/ecode/plugins/debugger/dap/protocol.hpp @@ -501,7 +501,8 @@ template <> struct std::hash { }; template <> struct std::hash { - std::size_t operator()( ecode::dap::SourceBreakpointStateful const& breakpoint ) const noexcept { + 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; diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index dda343f09..f6570ec90 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -4,7 +4,8 @@ namespace ecode { -static std::vector fromSet( const UnorderedSet& set ) { +std::vector +DebuggerClientListener::fromSet( const EE::UnorderedSet& set ) { std::vector bps; bps.reserve( set.size() ); for ( const auto& bp : set ) @@ -13,72 +14,6 @@ static std::vector fromSet( const UnorderedSetgetManager()->getUISceneNode()->runOnMainThread( [this] { - getStatusDebuggerController()->createWidget(); - - mPlugin->getManager() - ->getPluginContext() - ->getStatusAppOutputController() - ->initNewOutput( {}, false ); - } ); - } -} - -void DebuggerClientListener::initialized() { - Lock l( mPlugin->mBreakpointsMutex ); - for ( const auto& fileBps : mPlugin->mBreakpoints ) - mClient->setBreakpoints( fileBps.first, fromSet( fileBps.second ) ); -} - -void DebuggerClientListener::launched() {} - -void DebuggerClientListener::configured() {} - -void DebuggerClientListener::failed() {} - -void DebuggerClientListener::debuggeeRunning() {} - -void DebuggerClientListener::debuggeeTerminated() {} - -void DebuggerClientListener::capabilitiesReceived( const Capabilities& /*capabilities*/ ) {} - -void DebuggerClientListener::debuggeeExited( int /*exitCode*/ ) { - mPlugin->exitDebugger(); -} - -void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) { - Log::debug( "DebuggerClientListener::debuggeeStopped: reason %s", event.reason ); - mClient->threads(); - if ( event.threadId ) - mClient->stackTrace( *event.threadId ); -} - -void DebuggerClientListener::debuggeeContinued( const ContinuedEvent& ) {} - -void DebuggerClientListener::outputProduced( const Output& output ) { - if ( Output::Category::Stdout == output.category || - Output::Category::Stderr == output.category ) { - mPlugin->getManager()->getPluginContext()->getStatusAppOutputController()->insertBuffer( - output.output ); - } -} - -void DebuggerClientListener::debuggingProcess( const ProcessInfo& ) {} - -void DebuggerClientListener::errorResponse( const std::string& /*summary*/, - const std::optional& /*message*/ ) {} - -void DebuggerClientListener::threadChanged( const ThreadEvent& ) {} - -void DebuggerClientListener::moduleChanged( const ModuleEvent& ) {} - class ThreadsModel : public Model { public: ThreadsModel( const std::vector& threads ) : mThreads( threads ) {} @@ -102,16 +37,11 @@ class ThreadsModel : public Model { 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 size_t columnCount( const ModelIndex& ) const { return 6; } virtual std::string columnName( const size_t& colIdx ) const { switch ( colIdx ) { @@ -160,6 +90,99 @@ class StackModel : public Model { StackTraceInfo mStack; }; +DebuggerClientListener::DebuggerClientListener( DebuggerClient* client, DebuggerPlugin* plugin ) : + mClient( client ), mPlugin( plugin ) { + eeASSERT( mClient && mPlugin ); +} + +void DebuggerClientListener::stateChanged( DebuggerClient::State state ) { + if ( state == DebuggerClient::State::Initializing ) { + mPlugin->getManager()->getUISceneNode()->runOnMainThread( [this] { + getStatusDebuggerController()->createWidget(); + + mPlugin->getManager() + ->getPluginContext() + ->getStatusAppOutputController() + ->initNewOutput( {}, false ); + } ); + } +} + +void DebuggerClientListener::initialized() { + Lock l( mPlugin->mBreakpointsMutex ); + for ( const auto& fileBps : mPlugin->mBreakpoints ) + mClient->setBreakpoints( fileBps.first, fromSet( fileBps.second ) ); +} + +void DebuggerClientListener::launched() {} + +void DebuggerClientListener::configured() {} + +void DebuggerClientListener::failed() {} + +void DebuggerClientListener::debuggeeRunning() {} + +void DebuggerClientListener::debuggeeTerminated() {} + +void DebuggerClientListener::capabilitiesReceived( const Capabilities& /*capabilities*/ ) {} + +void DebuggerClientListener::debuggeeExited( int /*exitCode*/ ) { + mPlugin->exitDebugger(); +} + +void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) { + Log::debug( "DebuggerClientListener::debuggeeStopped: reason %s", event.reason ); + + mStoppedData = event; + + if ( mPausedToRefreshBreakpoints ) { + mPlugin->sendPendingBreakpoints(); + mClient->resume( 1 ); + mPausedToRefreshBreakpoints = false; + return; + } + + mClient->threads(); + + if ( event.threadId ) + mClient->stackTrace( *event.threadId ); +} + +void DebuggerClientListener::debuggeeContinued( const ContinuedEvent& ) { + mStoppedData = {}; + + // Reset models + mScope.clear(); + + getStatusDebuggerController()->getUIThreads()->setModel( + std::make_shared( std::vector{} ) ); + + getStatusDebuggerController()->getUIStack()->setModel( + std::make_shared( StackTraceInfo{} ) ); +} + +void DebuggerClientListener::outputProduced( const Output& output ) { + if ( Output::Category::Stdout == output.category || + Output::Category::Stderr == output.category ) { + mPlugin->getManager()->getPluginContext()->getStatusAppOutputController()->insertBuffer( + output.output ); + } +} + +void DebuggerClientListener::debuggingProcess( const ProcessInfo& ) {} + +void DebuggerClientListener::errorResponse( const std::string& /*summary*/, + const std::optional& /*message*/ ) {} + +void DebuggerClientListener::threadChanged( const ThreadEvent& ) {} + +void DebuggerClientListener::moduleChanged( const ModuleEvent& ) {} + +void DebuggerClientListener::threads( const std::vector& threads ) { + getStatusDebuggerController()->getUIThreads()->setModel( + std::make_shared( threads ) ); +} + void DebuggerClientListener::stackTrace( const int /*threadId*/, const StackTraceInfo& stack ) { getStatusDebuggerController()->getUIStack()->setModel( std::make_shared( stack ) ); @@ -168,17 +191,27 @@ void DebuggerClientListener::stackTrace( const int /*threadId*/, const StackTrac } } -void DebuggerClientListener::scopes( const int /*frameId**/, const std::vector& scopes ) { - // if ( !scopes.empty() ) { - // mClient->variables( scopes[0].variablesReference ); - // } +void DebuggerClientListener::scopes( const int /*frameId*/, const std::vector& scopes ) { + if ( !scopes.empty() ) { + for ( const auto& scope : scopes ) { + ModelScope mscope; + mscope.name = scope.name; + mscope.variablesReference = scope.variablesReference; + mScope.emplace_back( std::move( mscope ) ); + mClient->variables( scope.variablesReference ); + } + } } -void DebuggerClientListener::variables( const int /*variablesReference*/, +void DebuggerClientListener::variables( const int variablesReference, const std::vector& vars ) { - // if ( !vars.empty() ) { - // mClient->resume( 1 ); - // } + auto scopeIt = + std::find_if( mScope.begin(), mScope.end(), [variablesReference]( const ModelScope& cur ) { + return cur.variablesReference == variablesReference; + } ); + if ( scopeIt == mScope.end() ) + return; + scopeIt->variables = vars; } void DebuggerClientListener::modules( const ModulesInfo& ) {} @@ -199,14 +232,19 @@ void DebuggerClientListener::expressionEvaluated( const std::string& /*expressio void DebuggerClientListener::gotoTargets( const Source& /*source*/, const int /*line*/, const std::vector& /*targets*/ ) {} -StatusDebuggerController* DebuggerClientListener::getStatusDebuggerController() const { +bool DebuggerClientListener::isStopped() const { + return mStoppedData ? true : false; +} +std::optional DebuggerClientListener::getStoppedData() const { + return mStoppedData; +} + +StatusDebuggerController* DebuggerClientListener::getStatusDebuggerController() const { auto debuggerElement = mPlugin->getManager()->getPluginContext()->getStatusBar()->getStatusBarElement( "status_app_debugger" ); - - if ( !debuggerElement ) - return nullptr; + eeASSERT( debuggerElement ); return static_cast( debuggerElement.get() ); } diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp index 8d7f80c2e..08ee88b6e 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.hpp @@ -6,8 +6,17 @@ namespace ecode { class DebuggerPlugin; +struct ModelScope { + std::string name; + int variablesReference; + std::vector variables; +}; + class DebuggerClientListener : public DebuggerClient::Listener { public: + static std::vector + fromSet( const EE::UnorderedSet& set ); + DebuggerClientListener( DebuggerClient* client, DebuggerPlugin* plugin ); void stateChanged( DebuggerClient::State ); @@ -42,9 +51,18 @@ class DebuggerClientListener : public DebuggerClient::Listener { void gotoTargets( const Source& source, const int line, const std::vector& targets ); + bool isStopped() const; + + std::optional getStoppedData() const; + + void setPausedToRefreshBreakpoints() { mPausedToRefreshBreakpoints = true; } + protected: DebuggerClient* mClient{ nullptr }; DebuggerPlugin* mPlugin{ nullptr }; + std::optional mStoppedData; + std::vector mScope; + bool mPausedToRefreshBreakpoints{ false }; StatusDebuggerController* getStatusDebuggerController() const; }; diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index ffc3032e1..03858f0d2 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -170,11 +170,12 @@ void DebuggerPlugin::loadDAPConfig( const std::string& path, bool updateConfigFi } if ( mKeyBindings.empty() ) { + mKeyBindings["debugger-continue-interrupt"] = "f5"; } if ( j.contains( "keybindings" ) ) { auto& kb = j["keybindings"]; - std::initializer_list list = {}; + std::initializer_list list = { "debugger-continue-interrupt" }; for ( const auto& key : list ) { if ( kb.contains( key ) ) { if ( !kb[key].empty() ) @@ -325,13 +326,45 @@ void DebuggerPlugin::updateSidePanelTab() { if ( mDebugger && mDebugger->started() ) { exitDebugger(); } else { - runConfig( mUIDebuggerList->getListBox()->getItemSelectedText().toUtf8(), - mUIDebuggerConfList->getListBox()->getItemSelectedText().toUtf8() ); + runCurrentConfig(); } } ); } } +void DebuggerPlugin::runCurrentConfig() { + runConfig( mUIDebuggerList->getListBox()->getItemSelectedText().toUtf8(), + mUIDebuggerConfList->getListBox()->getItemSelectedText().toUtf8() ); +} + +void DebuggerPlugin::sendPendingBreakpoints() { + for ( const auto& pbp : mPendingBreakpoints ) + sendFileBreakpoints( pbp ); + mPendingBreakpoints.clear(); + if ( mDebugger ) + mDebugger->resume( 1 ); +} + +void DebuggerPlugin::sendFileBreakpoints( const std::string& filePath ) { + if ( !mDebugger || !mListener || !mDebugger->isServerConnected() ) + return; + + if ( !mListener->isStopped() ) { + mPendingBreakpoints.insert( filePath ); + mListener->setPausedToRefreshBreakpoints(); + mDebugger->pause( 1 ); + return; + } + + Lock l( mBreakpointsMutex ); + auto fileBps = mBreakpoints.find( filePath ); + if ( fileBps == mBreakpoints.end() ) + return; + for ( const auto& fileBps : mBreakpoints ) + mDebugger->setBreakpoints( fileBps.first, + DebuggerClientListener::fromSet( fileBps.second ) ); +} + void DebuggerPlugin::updateDebuggerConfigurationList() { mUIDebuggerConfList->getListBox()->clear(); @@ -392,8 +425,26 @@ void DebuggerPlugin::replaceKeysInJson( nlohmann::json& json ) { } } +void DebuggerPlugin::onRegisterDocument( TextDocument* doc ) { + doc->setCommand( "debugger-continue-interrupt", [this]() { + if ( mDebugger && mListener ) { + if ( mListener->isStopped() ) { + mDebugger->resume( mListener->getStoppedData()->threadId + ? *mListener->getStoppedData()->threadId + : 1 ); + } else { + mDebugger->pause( 1 ); + } + } else { + runCurrentConfig(); + } + } ); +} + void DebuggerPlugin::onRegisterEditor( UICodeEditor* editor ) { editor->registerGutterSpace( this, PixelDensity::dpToPx( 8 ), 0 ); + + PluginBase::onRegisterEditor( editor ); } void DebuggerPlugin::onUnregisterEditor( UICodeEditor* editor ) { @@ -441,9 +492,11 @@ void DebuggerPlugin::drawLineNumbersBefore( UICodeEditor* editor, radius ); } } + + } -bool DebuggerPlugin::onLineNumberClick( UICodeEditor* editor, Uint32 lineNumber ) { +bool DebuggerPlugin::setBreakpoint( UICodeEditor* editor, Uint32 lineNumber ) { if ( !editor->getDocument().hasFilepath() ) return false; if ( !isSupportedByAnyDebugger( editor->getDocument().getSyntaxDefinition().getLSPName() ) ) @@ -456,6 +509,8 @@ bool DebuggerPlugin::onLineNumberClick( UICodeEditor* editor, Uint32 lineNumber } else { breakpoints.insert( SourceBreakpointStateful( lineNumber ) ); } + mThreadPool->run( + [this, editor] { sendFileBreakpoints( editor->getDocument().getFilePath() ); } ); editor->invalidateDraw(); return true; } @@ -471,7 +526,7 @@ bool DebuggerPlugin::onMouseDown( UICodeEditor* editor, const Vector2i& position localPos.y > editor->getPluginsTopSpace() ) { if ( editor->getUISceneNode()->getEventDispatcher()->isFirstPress() ) { auto cursorPos( editor->resolveScreenPosition( position.asFloat() ) ); - onLineNumberClick( editor, cursorPos.line() ); + setBreakpoint( editor, cursorPos.line() ); } return true; } diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index cc1d133ae..f931c4f0b 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -65,6 +65,7 @@ class DebuggerPlugin : public PluginBase { UIDropDownList* mUIDebuggerConfList{ nullptr }; UIPushButton* mRunButton{ nullptr }; UnorderedMap> mBreakpoints; + UnorderedSet mPendingBreakpoints; Mutex mBreakpointsMutex; DebuggerPlugin( PluginManager* pluginManager, bool sync ); @@ -99,16 +100,23 @@ class DebuggerPlugin : public PluginBase { void onUnregisterEditor( UICodeEditor* ) override; + void onRegisterDocument( TextDocument* doc ) override; + void drawLineNumbersBefore( UICodeEditor* editor, const DocumentLineRange& lineRange, const Vector2f& startScroll, const Vector2f& screenStart, const Float& lineHeight, const Float& lineNumberWidth, const int& lineNumberDigits, const Float& fontSize ) override; - bool onLineNumberClick( UICodeEditor* editor, Uint32 lineNumber ); + bool setBreakpoint( UICodeEditor* editor, Uint32 lineNumber ); bool onMouseDown( UICodeEditor*, const Vector2i&, const Uint32& flags ) override; bool isSupportedByAnyDebugger( const std::string& language ); + + void runCurrentConfig(); + + void sendFileBreakpoints( const std::string& filePath ); + void sendPendingBreakpoints(); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp index d9f1f88fe..911be75c0 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp @@ -56,6 +56,20 @@ void StatusDebuggerController::createContainer() { mContainer->bind( "debugger_threads", mUIThreads ); mContainer->bind( "debugger_stack", mUIStack ); mContainer->bind( "debugger_breakpoints", mUIBreakpoints ); + + mContainer->runOnMainThread( [this] { + const Float width = mContainer->getPixelsSize().getWidth(); + + mUIThreads->setColumnWidth( 0, width * 0.1 ); + mUIThreads->setColumnWidth( 1, eefloor( width * 0.88 ) ); + + mUIStack->setColumnWidth( 0, width * 0.05 ); + mUIStack->setColumnWidth( 1, width * 0.3 ); + mUIStack->setColumnWidth( 2, width * 0.15 ); + mUIStack->setColumnWidth( 3, eefloor( width * 0.3 ) ); + mUIStack->setColumnWidth( 4, width * 0.08 ); + mUIStack->setColumnWidth( 5, width * 0.08 ); + } ); } } // namespace ecode diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 9729d5397..c59871e43 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -635,16 +635,6 @@ void GitPlugin::onRegisterListeners( UICodeEditor* editor, std::vector& } ) ); } -void GitPlugin::onBeforeUnregister( UICodeEditor* editor ) { - for ( auto& kb : mKeyBindings ) - editor->getKeyBindings().removeCommandKeybind( kb.first ); -} - -void GitPlugin::onUnregisterDocument( TextDocument* doc ) { - for ( auto& kb : mKeyBindings ) - doc->removeCommand( kb.first ); -} - Color GitPlugin::getVarColor( const std::string& var ) { return Color::fromString( getUISceneNode()->getRoot()->getUIStyle()->getVariable( var ).getValue() ); diff --git a/src/tools/ecode/plugins/git/gitplugin.hpp b/src/tools/ecode/plugins/git/gitplugin.hpp index 6ff77e4d5..05a38fe1a 100644 --- a/src/tools/ecode/plugins/git/gitplugin.hpp +++ b/src/tools/ecode/plugins/git/gitplugin.hpp @@ -147,10 +147,6 @@ class GitPlugin : public PluginBase { void onRegisterListeners( UICodeEditor*, std::vector& listeners ) override; - void onBeforeUnregister( UICodeEditor* ) override; - - void onUnregisterDocument( TextDocument* ) override; - Color getVarColor( const std::string& var ); void blame( UICodeEditor* editor ); diff --git a/src/tools/ecode/plugins/plugin.cpp b/src/tools/ecode/plugins/plugin.cpp index 550c10540..5d627ac9f 100644 --- a/src/tools/ecode/plugins/plugin.cpp +++ b/src/tools/ecode/plugins/plugin.cpp @@ -195,4 +195,21 @@ void PluginBase::onUnregister( UICodeEditor* editor ) { mDocs.erase( doc ); } +void PluginBase::onBeforeUnregister( UICodeEditor* editor ) { + for ( auto& kb : mKeyBindings ) + editor->getKeyBindings().removeCommandKeybind( kb.first ); +} + +void PluginBase::onRegisterEditor( UICodeEditor* editor ) { + for ( auto& kb : mKeyBindings ) { + if ( !kb.second.empty() ) + editor->getKeyBindings().addKeybindString( kb.second, kb.first ); + } +} + +void PluginBase::onUnregisterDocument( TextDocument* doc ) { + for ( auto& kb : mKeyBindings ) + doc->removeCommand( kb.first ); +} + } // namespace ecode diff --git a/src/tools/ecode/plugins/plugin.hpp b/src/tools/ecode/plugins/plugin.hpp index ad40a7f71..09c1cf26e 100644 --- a/src/tools/ecode/plugins/plugin.hpp +++ b/src/tools/ecode/plugins/plugin.hpp @@ -91,25 +91,26 @@ class PluginBase : public Plugin { //! If the configuration is stored in a file, keep track of the config hash String::HashType mConfigHash{ 0 }; - virtual void onDocumentLoaded( TextDocument* ) {}; + virtual void onDocumentLoaded( TextDocument* ) {} - virtual void onDocumentClosed( TextDocument* ) {}; + virtual void onDocumentClosed( TextDocument* ) {} virtual void onDocumentChanged( UICodeEditor*, TextDocument* /*oldDoc*/ ) {}; virtual void onRegisterListeners( UICodeEditor*, std::vector& /*listeners*/ ) {}; //! Usually used to remove keybindings in an editor - virtual void onBeforeUnregister( UICodeEditor* ) {}; + virtual void onBeforeUnregister( UICodeEditor* ); - virtual void onRegisterDocument( TextDocument* ) {}; + virtual void onRegisterDocument( TextDocument* ) {} - virtual void onRegisterEditor( UICodeEditor* ) {}; + virtual void onRegisterEditor( UICodeEditor* ); - virtual void onUnregisterEditor( UICodeEditor* ) {}; + virtual void onUnregisterEditor( UICodeEditor* ) {} //! Usually used to unregister commands in a document - virtual void onUnregisterDocument( TextDocument* ) {}; + virtual void onUnregisterDocument( TextDocument* ); + ; }; } // namespace ecode