More WIP.

This commit is contained in:
Martín Lucas Golini
2025-01-03 00:00:10 -03:00
parent 443aead0df
commit a96e033b81
14 changed files with 197 additions and 22 deletions

View File

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

View File

@@ -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() );

View File

@@ -611,13 +611,13 @@ bool DebuggerClientDap::evaluate( const std::string& expression, const std::stri
}
bool DebuggerClientDap::setBreakpoints( const std::string& path,
const std::vector<dap::SourceBreakpoint> breakpoints,
const std::vector<dap::SourceBreakpoint>& breakpoints,
bool sourceModified ) {
return setBreakpoints( Source( path ), breakpoints, sourceModified );
}
bool DebuggerClientDap::setBreakpoints( const dap::Source& source,
const std::vector<dap::SourceBreakpoint> breakpoints,
const std::vector<dap::SourceBreakpoint>& breakpoints,
bool sourceModified ) {
nlohmann::json bpoints = nlohmann::json::array();
for ( const auto& item : breakpoints )

View File

@@ -57,11 +57,11 @@ class DebuggerClientDap : public DebuggerClient {
bool supportsTerminate() const override;
bool setBreakpoints( const std::string& path,
const std::vector<dap::SourceBreakpoint> breakpoints,
const std::vector<dap::SourceBreakpoint>& breakpoints,
bool sourceModified = false ) override;
bool setBreakpoints( const dap::Source& source,
const std::vector<dap::SourceBreakpoint> breakpoints,
const std::vector<dap::SourceBreakpoint>& breakpoints,
bool sourceModified = false ) override;
bool gotoTargets( const std::string& path, const int line,

View File

@@ -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<ecode::dap::SourceBreakpoint> {
return hashCombine( h1, h2, h3, h4, h5 );
}
};
template <> struct std::hash<ecode::dap::SourceBreakpointStateful> {
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;
size_t h4 =
breakpoint.hitCondition ? std::hash<std::string>()( *breakpoint.hitCondition ) : 0;
size_t h5 = breakpoint.logMessage ? std::hash<std::string>()( *breakpoint.logMessage ) : 0;
size_t h6 = std::hash<bool>()( breakpoint.enabled );
return hashCombine( h1, h2, h3, h4, h5, h6 );
}
};

View File

@@ -89,11 +89,11 @@ class DebuggerClient {
virtual bool supportsTerminate() const = 0;
virtual bool setBreakpoints( const std::string& path,
const std::vector<dap::SourceBreakpoint> breakpoints,
const std::vector<dap::SourceBreakpoint>& breakpoints,
bool sourceModified = false ) = 0;
virtual bool setBreakpoints( const dap::Source& source,
const std::vector<dap::SourceBreakpoint> breakpoints,
const std::vector<dap::SourceBreakpoint>& breakpoints,
bool sourceModified = false ) = 0;
virtual bool gotoTargets( const std::string& path, const int line,

View File

@@ -4,6 +4,15 @@
namespace ecode {
static std::vector<SourceBreakpoint> fromSet( const UnorderedSet<SourceBreakpointStateful>& set ) {
std::vector<SourceBreakpoint> 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<Thread>& /*threads*/ ) {}
class ThreadsModel : public Model {
public:
ThreadsModel( const std::vector<Thread>& 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<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 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<StackModel>( stack ) );
if ( !stack.stackFrames.empty() ) {
mClient->scopes( stack.stackFrames[0].id );
}
}
void DebuggerClientListener::scopes( const int /*frameId**/, const std::vector<Scope>& scopes ) {
@@ -106,4 +199,15 @@ 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 {
auto debuggerElement =
mPlugin->getManager()->getPluginContext()->getStatusBar()->getStatusBarElement(
"status_app_debugger" );
if ( !debuggerElement )
return nullptr;
return static_cast<StatusDebuggerController*>( debuggerElement.get() );
}
} // namespace ecode

View File

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

View File

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

View File

@@ -64,7 +64,7 @@ class DebuggerPlugin : public PluginBase {
UIDropDownList* mUIDebuggerList{ nullptr };
UIDropDownList* mUIDebuggerConfList{ nullptr };
UIPushButton* mRunButton{ nullptr };
UnorderedMap<std::string, UnorderedSet<SourceBreakpoint>> mBreakpoints;
UnorderedMap<std::string, UnorderedSet<SourceBreakpointStateful>> mBreakpoints;
Mutex mBreakpointsMutex;
DebuggerPlugin( PluginManager* pluginManager, bool sync );

View File

@@ -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(
<hbox id="app_debugger" lw="mp" lh="mp" visible="false">
</hbox>
<TabWidget layout_width="match_parent" layout_height="0dp" layout_weight="1">
<TableView id="debugger_stack" layout_width="mp" layout_height="mp" />
<TableView id="debugger_threads" layout_width="mp" layout_height="mp" />
<TableView id="debugger_breakpoints" layout_width="mp" layout_height="mp" />
<Tab text="@string(stack, Stack)" owns="debugger_stack" />
<Tab text="@string(threads, Threads)" owns="debugger_threads" />
<Tab text="@string(breakpoints, Breakpoints)" owns="debugger_breakpoints" />
</TabWidget>
)xml";
if ( mMainSplitter->getLastWidget() != nullptr ) {
@@ -34,6 +52,10 @@ void StatusDebuggerController::createContainer() {
mContainer = mContext->getUISceneNode()
->loadLayoutFromString( XML, mMainSplitter )
->asType<UILinearLayout>();
mContainer->bind( "debugger_threads", mUIThreads );
mContainer->bind( "debugger_stack", mUIStack );
mContainer->bind( "debugger_breakpoints", mUIBreakpoints );
}
} // namespace ecode

View File

@@ -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();
};

View File

@@ -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 <eepp/ui/uiscenenode.hpp>
#include <eepp/window/window.hpp>
@@ -160,6 +160,13 @@ void UIStatusBar::setPluginContextProvider( PluginContextProvider* app ) {
updateState();
}
std::shared_ptr<StatusBarElement> 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() )

View File

@@ -51,6 +51,8 @@ class UIStatusBar : public UILinearLayout, public WidgetCommandExecuter {
void setPluginContextProvider( PluginContextProvider* app );
std::shared_ptr<StatusBarElement> getStatusBarElement( const std::string& id ) const;
protected:
UnorderedMap<std::string, std::pair<UIPushButton*, std::shared_ptr<StatusBarElement>>>
mElements;