diff --git a/src/tools/ecode/iconmanager.cpp b/src/tools/ecode/iconmanager.cpp index db50137ba..123b250b7 100644 --- a/src/tools/ecode/iconmanager.cpp +++ b/src/tools/ecode/iconmanager.cpp @@ -252,7 +252,15 @@ void IconManager::init( UISceneNode* sceneNode, FontTrueType* iconFont, FontTrue { "bug", 0xeaaf }, { "debug", 0xead8 }, { "debug-alt", 0xeb91 }, - }; + { "debug-continue", 0xeacf }, + { "debug-disconnect", 0xead0 }, + { "debug-pause", 0xead1 }, + { "debug-restart", 0xead2 }, + { "debug-start", 0xead3 }, + { "debug-step-into", 0xead4 }, + { "debug-step-out", 0xead5 }, + { "debug-step-over", 0xead6 }, + { "debug-stop", 0xead7 } }; for ( const auto& icon : codIcons ) iconTheme->add( UIGlyphIcon::New( icon.first, codIconFont, icon.second ) ); diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index 666896c24..c9a3d37ec 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -173,6 +173,7 @@ DebuggerClientListener::~DebuggerClientListener() { sdc->getUIThreads()->removeEventsOfType( Event::OnModelEvent ); if ( sdc->getUIStack() ) sdc->getUIStack()->removeEventsOfType( Event::OnModelEvent ); + mPlugin->setUIDebuggingState( StatusDebuggerController::State::NotStarted ); } } @@ -223,6 +224,8 @@ void DebuggerClientListener::stateChanged( DebuggerClient::State state ) { changeScope( stack ); } } ); + + mPlugin->setUIDebuggingState( StatusDebuggerController::State::Running ); } ); } } @@ -278,6 +281,8 @@ void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) { UISceneNode* sceneNode = mPlugin->getUISceneNode(); sceneNode->runOnMainThread( [sceneNode] { sceneNode->getWindow()->raise(); } ); + + mPlugin->setUIDebuggingState( StatusDebuggerController::State::Paused ); } void DebuggerClientListener::debuggeeContinued( const ContinuedEvent& ) { @@ -285,6 +290,8 @@ void DebuggerClientListener::debuggeeContinued( const ContinuedEvent& ) { UISceneNode* sceneNode = mPlugin->getUISceneNode(); sceneNode->runOnMainThread( [sceneNode] { sceneNode->invalidateDraw(); } ); + + mPlugin->setUIDebuggingState( StatusDebuggerController::State::Running ); } void DebuggerClientListener::outputProduced( const Output& output ) { diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index 9fc4e6503..66aaabd9e 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -151,6 +151,17 @@ void DebuggerPlugin::load( PluginManager* pluginManager ) { setReady( clock.getElapsedTime() ); } +static std::initializer_list DebuggerCommandList = { + "debugger-continue-interrupt", + "debugger-breakpoint-toggle", + "debugger-breakpoint-enable-toggle", + "debugger-stop", + "debugger-step-over", + "debugger-step-into", + "debugger-step-out", + "toggle-status-app-debugger", +}; + void DebuggerPlugin::loadDAPConfig( const std::string& path, bool updateConfigFile ) { std::string data; if ( !FileSystem::fileGet( path, data ) ) @@ -183,12 +194,16 @@ void DebuggerPlugin::loadDAPConfig( const std::string& path, bool updateConfigFi auto& run = dap["run"]; dapTool.run.command = run.value( "command", "" ); dapTool.fallbackCommand = run.value( "command_fallback", "" ); - if ( run.contains( "command_arguments" ) && run["command_arguments"].is_array() ) { - auto& args = run["command_arguments"]; - dapTool.run.args.reserve( args.size() ); - for ( auto& arg : args ) { - if ( args.is_string() ) - dapTool.run.args.emplace_back( arg.get() ); + if ( run.contains( "command_arguments" ) ) { + if ( run["command_arguments"].is_array() ) { + auto& args = run["command_arguments"]; + dapTool.run.args.reserve( args.size() ); + for ( auto& arg : args ) { + if ( args.is_string() ) + dapTool.run.args.emplace_back( arg.get() ); + } + } else if ( run["command_arguments"].is_string() ) { + dapTool.run.args.push_back( run["command_arguments"].get() ); } } } @@ -243,14 +258,7 @@ void DebuggerPlugin::loadDAPConfig( const std::string& path, bool updateConfigFi if ( j.contains( "keybindings" ) ) { auto& kb = j["keybindings"]; - std::initializer_list list = { "debugger-continue-interrupt", - "debugger-breakpoint-toggle", - "debugger-breakpoint-enable-toggle", - "debugger-step-over", - "debugger-step-into", - "debugger-step-out", - "toggle-status-app-debugger" }; - for ( const auto& key : list ) { + for ( const auto& key : DebuggerCommandList ) { if ( kb.contains( key ) ) { if ( !kb[key].empty() ) mKeyBindings[key] = kb[key]; @@ -511,6 +519,8 @@ void DebuggerPlugin::onRegisterDocument( TextDocument* doc ) { } } ); + doc->setCommand( "debugger-stop", [this] { exitDebugger(); } ); + doc->setCommand( "debugger-breakpoint-toggle", [doc, this] { if ( setBreakpoint( doc, doc->getSelection().start().line() ) ) getUISceneNode()->invalidateDraw(); @@ -545,17 +555,13 @@ void DebuggerPlugin::onRegisterDocument( TextDocument* doc ) { void DebuggerPlugin::onRegisterEditor( UICodeEditor* editor ) { editor->registerGutterSpace( this, PixelDensity::dpToPx( 8 ), 0 ); - editor->addUnlockedCommands( { "debugger-continue-interrupt", - "debugger-breakpoint-enable-toggle", - "toggle-status-app-debugger" } ); + editor->addUnlockedCommands( DebuggerCommandList ); PluginBase::onRegisterEditor( editor ); } void DebuggerPlugin::onUnregisterEditor( UICodeEditor* editor ) { - editor->removeUnlockedCommands( { "debugger-continue-interrupt", - "debugger-breakpoint-enable-toggle", - "toggle-status-app-debugger" } ); + editor->removeUnlockedCommands( DebuggerCommandList ); editor->unregisterGutterSpace( this ); } @@ -814,6 +820,9 @@ void DebuggerPlugin::runConfig( const std::string& debugger, const std::string& [this]( const Uint64& ) { if ( !mDebugger || !mDebugger->started() ) { exitDebugger(); + + getManager()->getPluginContext()->getNotificationCenter()->addNotification( + i18n( "debugger_init_failed", "Failed to initialize debugger." ) ); } else { mRunButton->runOnMainThread( [this] { mRunButton->setEnabled( true ); @@ -836,6 +845,8 @@ void DebuggerPlugin::exitDebugger() { mRunButton->setEnabled( true ); } ); } + + setUIDebuggingState( StatusDebuggerController::State::NotStarted ); } void DebuggerPlugin::hideSidePanel() { @@ -858,4 +869,11 @@ StatusDebuggerController* DebuggerPlugin::getStatusDebuggerController() const { getPluginContext()->getStatusBar()->getStatusBarElement( "status_app_debugger" ); return static_cast( debuggerElement.get() ); } + +void DebuggerPlugin::setUIDebuggingState( StatusDebuggerController::State state ) { + auto ctrl = getStatusDebuggerController(); + if ( ctrl ) + ctrl->setDebuggingState( state ); +} + } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index 46cdd3f88..29bcc63ab 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -126,6 +126,8 @@ class DebuggerPlugin : public PluginBase { void sendPendingBreakpoints(); StatusDebuggerController* getStatusDebuggerController() const; + + void setUIDebuggingState( StatusDebuggerController::State state ); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp index a8e0db9e9..8e6481c2f 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp @@ -30,19 +30,57 @@ UITableView* StatusDebuggerController::getUIBreakpoints() { return mUIBreakpoints; } +void StatusDebuggerController::setDebuggingState( State state ) { + if ( !mContainer ) + return; + + mUISceneNode->runOnMainThread( [this, state] { + mUIButStart->setVisible( state == State::NotStarted ) + ->setEnabled( state == State::NotStarted ); + mUIButStop->setVisible( state != State::NotStarted ) + ->setEnabled( state != State::NotStarted ); + mUIButContinue->setVisible( state != State::NotStarted ) + ->setEnabled( state == State::Paused ); + mUIButPause->setVisible( state != State::NotStarted ) + ->setEnabled( state == State::Running ); + mUIButStepOver->setVisible( state != State::NotStarted ) + ->setEnabled( state == State::Paused ); + mUIButStepInto->setVisible( state != State::NotStarted ) + ->setEnabled( state == State::Paused ); + mUIButStepOut->setVisible( state != State::NotStarted ) + ->setEnabled( state == State::Paused ); + } ); +} + void StatusDebuggerController::createContainer() { if ( mContainer ) return; const auto XML = R"xml( - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + )xml"; if ( mMainSplitter->getLastWidget() != nullptr ) { @@ -58,6 +96,32 @@ void StatusDebuggerController::createContainer() { mContainer->bind( "debugger_threads", mUIThreads ); mContainer->bind( "debugger_stack", mUIStack ); mContainer->bind( "debugger_breakpoints", mUIBreakpoints ); + mContainer->bind( "app_debugger_start", mUIButStart ); + mContainer->bind( "app_debugger_stop", mUIButStop ); + mContainer->bind( "app_debugger_pause", mUIButPause ); + mContainer->bind( "app_debugger_continue", mUIButContinue ); + mContainer->bind( "app_debugger_step_over", mUIButStepOver ); + mContainer->bind( "app_debugger_step_into", mUIButStepInto ); + mContainer->bind( "app_debugger_step_out", mUIButStepOut ); + + setDebuggingState( State::NotStarted ); + + mUIButStart->onClick( + [this]( auto ) { mContext->runCommand( "debugger-continue-interrupt" ); } ); + + mUIButContinue->onClick( + [this]( auto ) { mContext->runCommand( "debugger-continue-interrupt" ); } ); + + mUIButPause->onClick( + [this]( auto ) { mContext->runCommand( "debugger-continue-interrupt" ); } ); + + mUIButStop->onClick( [this]( auto ) { mContext->runCommand( "debugger-stop" ); } ); + + mUIButStepOver->onClick( [this]( auto ) { mContext->runCommand( "debugger-step-over" ); } ); + + mUIButStepInto->onClick( [this]( auto ) { mContext->runCommand( "debugger-step-into" ); } ); + + mUIButStepOut->onClick( [this]( auto ) { mContext->runCommand( "debugger-step-out" ); } ); mUIThreads->setAutoExpandOnSingleColumn( true ); diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp index 3a4c7bd1a..dff99b693 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp @@ -18,6 +18,8 @@ namespace ecode { class StatusDebuggerController : public StatusBarElement { public: + enum class State { NotStarted, Running, Paused }; + StatusDebuggerController( UISplitter* mainSplitter, UISceneNode* uiSceneNode, PluginContextProvider* pluginContext ); @@ -33,12 +35,21 @@ class StatusDebuggerController : public StatusBarElement { UITableView* getUIBreakpoints(); + void setDebuggingState( State state ); + protected: UILinearLayout* mContainer{ nullptr }; UITableView* mUIThreads{ nullptr }; UITableView* mUIStack{ nullptr }; UITableView* mUIBreakpoints{ nullptr }; UISplitter* mUIThreadsSplitter{ nullptr }; + UIPushButton* mUIButStart{ nullptr }; + UIPushButton* mUIButStop{ nullptr }; + UIPushButton* mUIButContinue{ nullptr }; + UIPushButton* mUIButPause{ nullptr }; + UIPushButton* mUIButStepInto{ nullptr }; + UIPushButton* mUIButStepOver{ nullptr }; + UIPushButton* mUIButStepOut{ nullptr }; void createContainer(); }; diff --git a/src/tools/ecode/plugins/plugincontextprovider.hpp b/src/tools/ecode/plugins/plugincontextprovider.hpp index ca0f08835..57d0391b3 100644 --- a/src/tools/ecode/plugins/plugincontextprovider.hpp +++ b/src/tools/ecode/plugins/plugincontextprovider.hpp @@ -118,6 +118,8 @@ class PluginContextProvider { virtual std::string getCurrentWorkingDir() const = 0; virtual void focusOrLoadFile( const std::string& path, const TextRange& range = {} ) = 0; + + virtual void runCommand( const std::string& command ) = 0; }; } // namespace ecode