diff --git a/include/eepp/scene/node.hpp b/include/eepp/scene/node.hpp index 91b3d7c85..d9cc7cf25 100644 --- a/include/eepp/scene/node.hpp +++ b/include/eepp/scene/node.hpp @@ -404,19 +404,33 @@ class EE_API Node : public Transformable { Uint32 getNodeOfTypeIndex() const; + //! Enqueues the runnable to be executed on the main thread (during the scene node update). + //! It will always be equeued to the main thread execution queue (a.k.a. actions). void runOnMainThread( Actions::Runnable::RunnableFunc runnable, const Time& delay = Seconds( 0 ), const Action::UniqueID& uniqueIdentifier = 0 ); + //! Does the same as runOnMainThread if called from a none main thread, otherwise it will be + //! executed inmediatelly. + //! @return True if runnable was inmediatelly executed. + bool ensureMainThread( Actions::Runnable::RunnableFunc runnable, + const Action::UniqueID& uniqueIdentifier = 0 ); + + //! Enqueues the runnable to be run after delay time. void setTimeout( Actions::Runnable::RunnableFunc runnable, const Time& delay = Seconds( 0 ), const Action::UniqueID& uniqueIdentifier = 0 ); - void debounce( Actions::Runnable::RunnableFunc runnable, const Time& delay, - const Action::UniqueID& uniqueIdentifier ); - + //! Repeatedly calls executes the runnable, with a fixed time delay between each call. void setInterval( Actions::Runnable::RunnableFunc runnable, const Time& interval, const Action::UniqueID& uniqueIdentifier = 0 ); + //! Enqueues a runnable to be executed in delay time with a unique identifier, if a new runnable + //! is provided before the delay passed, previous enqueue runnable will be removed and the new + //! one will be enqueued, if no other runnable with the same identifier is enqueued until delay + //! passed, the last runnable will be executed. + void debounce( Actions::Runnable::RunnableFunc runnable, const Time& delay, + const Action::UniqueID& uniqueIdentifier ); + bool isChild( Node* child ) const; bool inParentTreeOf( Node* child ) const; diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index 5a663ba6e..4d2ddb1d1 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace EE { namespace Scene { @@ -1591,6 +1592,19 @@ void Node::runOnMainThread( Actions::Runnable::RunnableFunc runnable, const Time runAction( action ); } +bool Node::ensureMainThread( Actions::Runnable::RunnableFunc runnable, + const Action::UniqueID& uniqueIdentifier ) { + if ( Engine::isRunninMainThread() ) { + runnable(); + return true; + } else { + Action* action = Actions::Runnable::New( std::move( runnable ) ); + action->setTag( uniqueIdentifier ); + runAction( action ); + } + return false; +} + void Node::setTimeout( Actions::Runnable::RunnableFunc runnable, const Time& delay, const Action::UniqueID& uniqueIdentifier ) { Action* action = Actions::Runnable::New( std::move( runnable ), delay ); diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index bb49ec12c..939bf125b 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -48,6 +48,8 @@ void DebuggerClientListener::initUI() { mPlugin->getManager()->getPluginContext()->getStatusAppOutputController()->initNewOutput( {}, false ); + sdc->clearConsoleBuffer(); + UISceneNode* sceneNode = mPlugin->getUISceneNode(); if ( !mThreadsModel ) { @@ -152,12 +154,11 @@ void DebuggerClientListener::debuggeeExited( int /*exitCode*/ ) { void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) { Log::debug( "DebuggerClientListener::debuggeeStopped: reason %s", event.reason ); - int threadId = mStoppedData->threadId ? *mStoppedData->threadId : 1; + mCurrentThreadId = mStoppedData->threadId ? *mStoppedData->threadId : 1; mStoppedData = event; if ( mPausedToRefreshBreakpoints ) { mPlugin->sendPendingBreakpoints(); - mClient->resume( threadId ); mPausedToRefreshBreakpoints = false; return; } @@ -190,6 +191,20 @@ void DebuggerClientListener::outputProduced( const Output& output ) { if ( Output::Category::Stdout == output.category || Output::Category::Stderr == output.category ) { mPlugin->getPluginContext()->getStatusAppOutputController()->insertBuffer( output.output ); + } else if ( Output::Category::Console == output.category ) { + auto buffer = output.output; + auto sdc = getStatusDebuggerController(); + if ( sdc == nullptr || sdc->getUIConsole() == nullptr ) { + mPlugin->getUISceneNode()->runOnMainThread( + [this, buffer = std::move( buffer )]() mutable { + mPlugin->initStatusDebuggerController(); + auto sdc = getStatusDebuggerController(); + sdc->insertConsoleBuffer( std::move( buffer ) ); + } ); + return; + } else { + sdc->insertConsoleBuffer( std::move( buffer ) ); + } } } diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index 624ea7dc0..1fff332b4 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -875,7 +875,7 @@ void DebuggerPlugin::sendPendingBreakpoints() { sendFileBreakpoints( pbp ); mPendingBreakpoints.clear(); if ( mDebugger ) - mDebugger->resume( 1 ); + mDebugger->resume( mListener->getCurrentThreadId() ); } void DebuggerPlugin::sendFileBreakpoints( const std::string& filePath ) { @@ -1194,15 +1194,12 @@ void DebuggerPlugin::drawLineNumbersBefore( UICodeEditor* editor, bool DebuggerPlugin::setBreakpoint( const std::string& doc, Uint32 lineNumber ) { Lock l( mBreakpointsMutex ); - auto sdc = getStatusDebuggerController(); - if ( sdc && sdc->getWidget() == nullptr ) { - sdc->show(); - sdc->hide(); - } + initStatusDebuggerController(); if ( !mBreakpointsModel ) mBreakpointsModel = std::make_shared( mBreakpoints, getUISceneNode() ); + auto sdc = getStatusDebuggerController(); if ( sdc && sdc->getUIBreakpoints()->getModel() == nullptr ) sdc->getUIBreakpoints()->setModel( mBreakpointsModel ); @@ -1427,6 +1424,14 @@ DebuggerPlugin::debuggerBinaryExists( const std::string& debugger, return cmd; } +void DebuggerPlugin::initStatusDebuggerController() { + auto sdc = getStatusDebuggerController(); + if ( sdc && sdc->getWidget() == nullptr ) { + sdc->show(); + sdc->hide(); + } +} + void DebuggerPlugin::run( const std::string& debugger, ProtocolSettings&& protocolSettings, DapRunConfig&& runConfig, int /*randPort*/ ) { std::optional cmdOpt = debuggerBinaryExists( debugger, runConfig ); diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index b35fda66e..79726bc6d 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -67,6 +67,8 @@ class DebuggerPlugin : public PluginBase { std::optional debuggerBinaryExists( const std::string& debugger, std::optional runConfig = {} ); + void initStatusDebuggerController(); + protected: friend class DebuggerClientListener; diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp index 326b2b11d..742de12a8 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp @@ -104,6 +104,21 @@ UITabWidget* StatusDebuggerController::getUITabWidget() const { return mUITabWidget; } +UICodeEditor* StatusDebuggerController::getUIConsole() const { + return mUIConsole; +} + +void StatusDebuggerController::insertConsoleBuffer( std::string&& buffer ) { + auto console = getUIConsole(); + if ( console == nullptr ) + return; + console->runOnMainThread( [console, this, buffer = std::move( buffer )]() { + console->getDocument().insert( 0, console->getDocument().endOfDoc(), buffer ); + if ( getConsoleScrollLocked() ) + console->setScrollY( console->getMaxScroll().y ); + } ); +} + void StatusDebuggerController::setDebuggingState( State state ) { if ( !mContainer ) return; @@ -126,6 +141,16 @@ void StatusDebuggerController::setDebuggingState( State state ) { } ); } +void StatusDebuggerController::clearConsoleBuffer() { + if ( mUIConsole == nullptr ) + return; + mUIConsole->runOnMainThread( [this] { + mUIConsole->getDocument().reset(); + mUIConsole->invalidateLongestLineWidth(); + mUIConsole->setScrollY( mUIConsole->getMaxScroll().y ); + } ); +} + void StatusDebuggerController::createContainer() { if ( mContainer ) return; @@ -144,10 +169,12 @@ void StatusDebuggerController::createContainer() { + + @@ -179,6 +206,7 @@ void StatusDebuggerController::createContainer() { mContainer->bind( "debugger_breakpoints", mUIBreakpoints ); mContainer->bind( "debugger_variables", mUIVariables ); mContainer->bind( "debugger_expressions", mUIExpressions ); + mContainer->bind( "debugger_console", mUIConsole ); mContainer->bind( "app_debugger_start", mUIButStart ); mContainer->bind( "app_debugger_stop", mUIButStop ); mContainer->bind( "app_debugger_pause", mUIButPause ); @@ -222,6 +250,15 @@ void StatusDebuggerController::createContainer() { mUIExpressions->setAutoColumnsWidth( true ); mUIExpressions->setFitAllColumnsToWidget( true ); mUIExpressions->setMainColumn( 1 ); + + mUIConsole->setLocked( true ); + mUIConsole->setLineBreakingColumn( 0 ); + mUIConsole->setShowLineNumber( false ); + mUIConsole->getDocument().reset(); + mUIConsole->setScrollY( mUIConsole->getMaxScroll().y ); + mUIConsole->on( Event::OnScrollChange, [this]( auto ) { + mScrollLocked = mUIConsole->getMaxScroll().y == mUIConsole->getScroll().y; + } ); } } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp index 2e63a957d..1f305c6ad 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.hpp @@ -60,6 +60,14 @@ class StatusDebuggerController : public StatusBarElement { UITabWidget* getUITabWidget() const; + UICodeEditor* getUIConsole() const; + + bool getConsoleScrollLocked() const { return mScrollLocked; } + + void insertConsoleBuffer( std::string&& buffer ); + + void clearConsoleBuffer(); + void setDebuggingState( State state ); std::function onWidgetCreated{ nullptr }; @@ -72,6 +80,7 @@ class StatusDebuggerController : public StatusBarElement { UITreeView* mUIVariables{ nullptr }; UITreeView* mUIExpressions{ nullptr }; UISplitter* mUIThreadsSplitter{ nullptr }; + UICodeEditor* mUIConsole{ nullptr }; UIPushButton* mUIButStart{ nullptr }; UIPushButton* mUIButStop{ nullptr }; UIPushButton* mUIButContinue{ nullptr }; @@ -80,6 +89,7 @@ class StatusDebuggerController : public StatusBarElement { UIPushButton* mUIButStepOver{ nullptr }; UIPushButton* mUIButStepOut{ nullptr }; UITabWidget* mUITabWidget{ nullptr }; + bool mScrollLocked{ true }; void createContainer(); };