Still more WIP

This commit is contained in:
Martín Lucas Golini
2025-01-03 22:01:16 -03:00
parent a96e033b81
commit c4bd88461d
10 changed files with 251 additions and 113 deletions

View File

@@ -501,7 +501,8 @@ template <> struct std::hash<ecode::dap::SourceBreakpoint> {
};
template <> struct std::hash<ecode::dap::SourceBreakpointStateful> {
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<int>()( breakpoint.line );
size_t h2 = breakpoint.column ? std::hash<int>()( *breakpoint.column ) : 0;
size_t h3 = breakpoint.condition ? std::hash<std::string>()( *breakpoint.condition ) : 0;

View File

@@ -4,7 +4,8 @@
namespace ecode {
static std::vector<SourceBreakpoint> fromSet( const UnorderedSet<SourceBreakpointStateful>& set ) {
std::vector<SourceBreakpoint>
DebuggerClientListener::fromSet( const EE::UnorderedSet<SourceBreakpointStateful>& set ) {
std::vector<SourceBreakpoint> bps;
bps.reserve( set.size() );
for ( const auto& bp : set )
@@ -13,72 +14,6 @@ static std::vector<SourceBreakpoint> fromSet( const UnorderedSet<SourceBreakpoin
return bps;
}
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 );
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>& /*message*/ ) {}
void DebuggerClientListener::threadChanged( const ThreadEvent& ) {}
void DebuggerClientListener::moduleChanged( const ModuleEvent& ) {}
class ThreadsModel : public Model {
public:
ThreadsModel( const std::vector<Thread>& threads ) : mThreads( threads ) {}
@@ -102,16 +37,11 @@ class ThreadsModel : public Model {
std::vector<Thread> mThreads;
};
void DebuggerClientListener::threads( const std::vector<Thread>& threads ) {
getStatusDebuggerController()->getUIThreads()->setModel(
std::make_shared<ThreadsModel>( 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<ThreadsModel>( std::vector<Thread>{} ) );
getStatusDebuggerController()->getUIStack()->setModel(
std::make_shared<StackModel>( 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>& /*message*/ ) {}
void DebuggerClientListener::threadChanged( const ThreadEvent& ) {}
void DebuggerClientListener::moduleChanged( const ModuleEvent& ) {}
void DebuggerClientListener::threads( const std::vector<Thread>& threads ) {
getStatusDebuggerController()->getUIThreads()->setModel(
std::make_shared<ThreadsModel>( threads ) );
}
void DebuggerClientListener::stackTrace( const int /*threadId*/, const StackTraceInfo& stack ) {
getStatusDebuggerController()->getUIStack()->setModel( std::make_shared<StackModel>( stack ) );
@@ -168,17 +191,27 @@ void DebuggerClientListener::stackTrace( const int /*threadId*/, const StackTrac
}
}
void DebuggerClientListener::scopes( const int /*frameId**/, const std::vector<Scope>& scopes ) {
// if ( !scopes.empty() ) {
// mClient->variables( scopes[0].variablesReference );
// }
void DebuggerClientListener::scopes( const int /*frameId*/, const std::vector<Scope>& 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<Variable>& 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<GotoTarget>& /*targets*/ ) {}
StatusDebuggerController* DebuggerClientListener::getStatusDebuggerController() const {
bool DebuggerClientListener::isStopped() const {
return mStoppedData ? true : false;
}
std::optional<StoppedEvent> 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<StatusDebuggerController*>( debuggerElement.get() );
}

View File

@@ -6,8 +6,17 @@ namespace ecode {
class DebuggerPlugin;
struct ModelScope {
std::string name;
int variablesReference;
std::vector<Variable> variables;
};
class DebuggerClientListener : public DebuggerClient::Listener {
public:
static std::vector<SourceBreakpoint>
fromSet( const EE::UnorderedSet<SourceBreakpointStateful>& 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<GotoTarget>& targets );
bool isStopped() const;
std::optional<StoppedEvent> getStoppedData() const;
void setPausedToRefreshBreakpoints() { mPausedToRefreshBreakpoints = true; }
protected:
DebuggerClient* mClient{ nullptr };
DebuggerPlugin* mPlugin{ nullptr };
std::optional<StoppedEvent> mStoppedData;
std::vector<ModelScope> mScope;
bool mPausedToRefreshBreakpoints{ false };
StatusDebuggerController* getStatusDebuggerController() const;
};

View File

@@ -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<std::string> list = {};
std::initializer_list<std::string> 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;
}

View File

@@ -65,6 +65,7 @@ class DebuggerPlugin : public PluginBase {
UIDropDownList* mUIDebuggerConfList{ nullptr };
UIPushButton* mRunButton{ nullptr };
UnorderedMap<std::string, UnorderedSet<SourceBreakpointStateful>> mBreakpoints;
UnorderedSet<std::string> 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

View File

@@ -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

View File

@@ -635,16 +635,6 @@ void GitPlugin::onRegisterListeners( UICodeEditor* editor, std::vector<Uint32>&
} ) );
}
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() );

View File

@@ -147,10 +147,6 @@ class GitPlugin : public PluginBase {
void onRegisterListeners( UICodeEditor*, std::vector<Uint32>& listeners ) override;
void onBeforeUnregister( UICodeEditor* ) override;
void onUnregisterDocument( TextDocument* ) override;
Color getVarColor( const std::string& var );
void blame( UICodeEditor* editor );

View File

@@ -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

View File

@@ -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<Uint32>& /*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