mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
More WIP, debugger starting correctly. Tested several commands and all working.
This commit is contained in:
@@ -15,7 +15,8 @@
|
||||
"args": "${args}",
|
||||
"cwd": "${cwd}",
|
||||
"env": "${env}",
|
||||
"stopOnEntry": "${stopOnEntry}"
|
||||
"stopOnEntry": "${stopOnEntry}",
|
||||
"stopAtBeginningOfMainSubprogram": false
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -44,6 +44,8 @@ class EE_API Process {
|
||||
|
||||
typedef std::function<void( const char* bytes, size_t n )> ReadFn;
|
||||
|
||||
static std::vector<std::string> parseArgs( const std::string& str );
|
||||
|
||||
Process();
|
||||
|
||||
/** @brief Create a process.
|
||||
|
||||
@@ -42,7 +42,7 @@ static bool isFlatpakEnv() {
|
||||
|
||||
#define PROCESS_PTR ( static_cast<struct subprocess_s*>( mProcess ) )
|
||||
|
||||
static std::vector<std::string> parseArgs( const std::string& str ) {
|
||||
std::vector<std::string> Process::parseArgs( const std::string& str ) {
|
||||
bool inquote = false;
|
||||
char quoteChar = 0;
|
||||
std::vector<std::string> res;
|
||||
|
||||
@@ -396,6 +396,10 @@ void UIConsole::setMaxLogLines( const Uint32& maxLogLines ) {
|
||||
|
||||
void UIConsole::privPushText( String&& str ) {
|
||||
Lock l( mMutex );
|
||||
if ( str.find_first_of( '\r' ) != String::InvalidPos )
|
||||
String::replaceAll( str, "\r", "" );
|
||||
if ( str.empty() )
|
||||
return;
|
||||
mCmdLog.push_back( { std::move( str ), String::hash( str ) } );
|
||||
if ( mVisible )
|
||||
invalidateDraw();
|
||||
|
||||
@@ -20,6 +20,8 @@ class Bus {
|
||||
|
||||
virtual size_t write( const char* buffer, const size_t& size ) = 0;
|
||||
|
||||
virtual ~Bus() {}
|
||||
|
||||
protected:
|
||||
void setState( State state );
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@ DebuggerClientDap::DebuggerClientDap( const ProtocolSettings& protocolSettings,
|
||||
std::unique_ptr<Bus>&& bus ) :
|
||||
mBus( std::move( bus ) ), mProtocol( protocolSettings ) {}
|
||||
|
||||
DebuggerClientDap::~DebuggerClientDap() {
|
||||
mBus.reset();
|
||||
}
|
||||
|
||||
void DebuggerClientDap::makeRequest( const std::string_view& command,
|
||||
const nlohmann::json& arguments, ResponseHandler onFinish ) {
|
||||
nlohmann::json jsonCmd = {
|
||||
@@ -31,10 +35,12 @@ void DebuggerClientDap::makeRequest( const std::string_view& command,
|
||||
{ "arguments", arguments.empty() ? nlohmann::json::object() : arguments } };
|
||||
|
||||
std::string cmd = jsonCmd.dump();
|
||||
|
||||
Log::instance()->writel( mDebug ? LogLevel::Info : LogLevel::Debug, cmd );
|
||||
|
||||
std::string msg( String::format( "Content-Length: %zu\r\n\r\n%s", cmd.size(), cmd ) );
|
||||
|
||||
Log::instance()->writel( mDebug ? LogLevel::Info : LogLevel::Debug,
|
||||
"DebuggerClientDap::makeRequest:" );
|
||||
Log::instance()->writel( mDebug ? LogLevel::Info : LogLevel::Debug, msg );
|
||||
|
||||
mBus->write( msg.data(), msg.size() );
|
||||
|
||||
mRequests[mIdx] = { std::string{ command }, arguments, onFinish };
|
||||
@@ -113,9 +119,9 @@ void DebuggerClientDap::requestLaunchCommand() {
|
||||
[this]( const Response& response, const auto& ) {
|
||||
if ( response.success ) {
|
||||
mLaunched = true;
|
||||
checkRunning();
|
||||
for ( auto listener : mListeners )
|
||||
listener->launched();
|
||||
checkRunning();
|
||||
} else {
|
||||
if ( response.errorBody ) {
|
||||
Log::warning( "DebuggerClientDap::requestLaunchCommand: error %ld %s",
|
||||
@@ -131,7 +137,7 @@ void DebuggerClientDap::requestInitialize() {
|
||||
{ DAP_CLIENT_ID, "ecode-dap" },
|
||||
{ DAP_CLIENT_NAME, "ecode dap" },
|
||||
{ "locale", mProtocol.locale },
|
||||
{ DAP_ADAPTER_ID, "qdap" },
|
||||
{ DAP_ADAPTER_ID, "ecode-dap" },
|
||||
{ DAP_LINES_START_AT1, mProtocol.linesStartAt1 },
|
||||
{ DAP_COLUMNS_START_AT2, mProtocol.columnsStartAt1 },
|
||||
{ DAP_PATH, ( mProtocol.pathFormatURI ? DAP_URI : DAP_PATH ) },
|
||||
@@ -166,8 +172,10 @@ void DebuggerClientDap::asyncRead( const char* bytes, size_t n ) {
|
||||
#endif
|
||||
auto message = json::parse( data );
|
||||
|
||||
if ( mDebug )
|
||||
if ( mDebug ) {
|
||||
Log::debug( "DebuggerClientDap::asyncRead:" );
|
||||
Log::debug( message.dump() );
|
||||
}
|
||||
|
||||
processProtocolMessage( message );
|
||||
#ifndef EE_DEBUG
|
||||
@@ -229,7 +237,7 @@ void DebuggerClientDap::errorResponse( const std::string& summary,
|
||||
|
||||
void DebuggerClientDap::processEvent( const nlohmann::json& msg ) {
|
||||
const std::string event = msg.value( DAP_EVENT, "" );
|
||||
const auto body = msg[DAP_BODY];
|
||||
const auto body = msg.contains( DAP_BODY ) ? msg[DAP_BODY] : nlohmann::json{};
|
||||
|
||||
if ( "initialized"sv == event ) {
|
||||
processEventInitialized();
|
||||
@@ -262,6 +270,8 @@ void DebuggerClientDap::processEventInitialized() {
|
||||
return;
|
||||
}
|
||||
setState( State::Initialized );
|
||||
|
||||
configurationDone();
|
||||
}
|
||||
|
||||
void DebuggerClientDap::processEventTerminated() {
|
||||
@@ -337,7 +347,8 @@ std::optional<DebuggerClientDap::HeaderInfo> DebuggerClientDap::readHeader() {
|
||||
}
|
||||
|
||||
const auto header = mBuffer.substr( start, end - start );
|
||||
end += DAP_SEP_SIZE;
|
||||
while ( std::string_view{ mBuffer }.substr( end, 2 ) == DAP_SEP )
|
||||
end += DAP_SEP_SIZE;
|
||||
|
||||
// header block separator
|
||||
if ( header.size() == 0 ) {
|
||||
@@ -362,18 +373,19 @@ std::optional<DebuggerClientDap::HeaderInfo> DebuggerClientDap::readHeader() {
|
||||
if ( String::startsWith( header, DAP_CONTENT_LENGTH ) ) {
|
||||
std::string lengthStr( header.substr( sep + 1, header.size() - sep ) );
|
||||
String::trimInPlace( lengthStr );
|
||||
Uint64 length;
|
||||
if ( !String::fromString( length, lengthStr ) ) {
|
||||
Log::error( "DebuggerClientDap::readHeader invalid value: ", header );
|
||||
discardExploredBuffer();
|
||||
continue; // CONTINUE HEADER
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
start = end;
|
||||
}
|
||||
|
||||
if ( length < 0 )
|
||||
if ( length < 0 || length == std::string::npos )
|
||||
return std::nullopt;
|
||||
|
||||
return HeaderInfo{ end, length };
|
||||
@@ -683,4 +695,30 @@ bool DebuggerClientDap::watch( const std::string& expression, std::optional<int>
|
||||
return evaluate( expression, "watch", frameId );
|
||||
}
|
||||
|
||||
bool DebuggerClientDap::configurationDone() {
|
||||
if ( mState != State::Initialized ) {
|
||||
Log::warning( "DebuggerClientDap::requestConfigurationDone: trying to configure in an "
|
||||
"unexpected status" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !mAdapterCapabilities.supportsConfigurationDoneRequest ) {
|
||||
for ( auto listener : mListeners )
|
||||
listener->configured();
|
||||
return true;
|
||||
}
|
||||
|
||||
makeRequest( "configurationDone", nlohmann::json{},
|
||||
[this]( const auto& response, const auto& ) {
|
||||
if ( response.success ) {
|
||||
mConfigured = true;
|
||||
checkRunning();
|
||||
for ( auto listener : mListeners )
|
||||
listener->configured();
|
||||
}
|
||||
} );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ecode::dap
|
||||
|
||||
@@ -18,6 +18,8 @@ class DebuggerClientDap : public DebuggerClient {
|
||||
|
||||
DebuggerClientDap( const ProtocolSettings& protocolSettings, std::unique_ptr<Bus>&& bus );
|
||||
|
||||
virtual ~DebuggerClientDap();
|
||||
|
||||
bool start() override;
|
||||
|
||||
bool resume( int threadId, bool singleThread = false ) override;
|
||||
@@ -38,11 +40,12 @@ class DebuggerClientDap : public DebuggerClient {
|
||||
|
||||
bool threads() override;
|
||||
|
||||
bool stackTrace( int threadId, int startFrame, int levels ) override;
|
||||
bool stackTrace( int threadId, int startFrame = 0, int levels = 0 ) override;
|
||||
|
||||
bool scopes( int frameId ) override;
|
||||
|
||||
bool variables( int variablesReference, Variable::Type filter, int start, int count ) override;
|
||||
bool variables( int variablesReference, Variable::Type filter = Variable::Type::Both,
|
||||
int start = 0, int count = 0 ) override;
|
||||
|
||||
bool modules( int start, int count ) override;
|
||||
|
||||
@@ -69,6 +72,8 @@ class DebuggerClientDap : public DebuggerClient {
|
||||
|
||||
bool watch( const std::string& expression, std::optional<int> frameId ) override;
|
||||
|
||||
bool configurationDone() override;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<Bus> mBus;
|
||||
UnorderedMap<std::string, UnorderedSet<int>> mBreakpoints;
|
||||
@@ -131,6 +136,7 @@ class DebuggerClientDap : public DebuggerClient {
|
||||
void requestLaunchCommand();
|
||||
|
||||
void processResponseInitialize( const Response& response, const nlohmann::json& );
|
||||
|
||||
void processResponseNext( const Response& response, const nlohmann::json& request );
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "messages.hpp"
|
||||
#include "protocol.hpp"
|
||||
#include "messages.hpp"
|
||||
#include <eepp/core/core.hpp>
|
||||
#include <eepp/system/fileinfo.hpp>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
@@ -7,40 +7,46 @@
|
||||
using namespace EE;
|
||||
using namespace EE::System;
|
||||
|
||||
std::optional<int> parseOptionalInt( const json& value ) {
|
||||
if ( value.is_null() || value.empty() || !value.is_number() ) {
|
||||
std::optional<int> parseOptionalInt( const json& value, const std::string_view& name ) {
|
||||
if ( !value.contains( name ) || value[name].is_null() || value[name].empty() ||
|
||||
!value[name].is_number() ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return value.get<int>();
|
||||
return value[name].get<int>();
|
||||
}
|
||||
|
||||
std::optional<bool> parseOptionalBool( const json& value ) {
|
||||
if ( value.is_null() || value.empty() || !value.is_boolean() ) {
|
||||
std::optional<bool> parseOptionalBool( const json& value, const std::string_view& name ) {
|
||||
if ( !value.contains( name ) || value[name].is_null() || value[name].empty() ||
|
||||
!value[name].is_boolean() ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return value.get<bool>();
|
||||
return value[name].get<bool>();
|
||||
}
|
||||
|
||||
std::optional<std::string> parseOptionalString( const json& value ) {
|
||||
if ( value.is_null() || value.empty() || !value.is_string() ) {
|
||||
std::optional<std::string> parseOptionalString( const json& value, const std::string_view& name ) {
|
||||
if ( !value.contains( name ) || value[name].is_null() || value[name].empty() ||
|
||||
!value[name].is_string() ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return value.get<std::string>();
|
||||
return value[name].get<std::string>();
|
||||
}
|
||||
|
||||
template <typename T> std::optional<T> parseOptionalObject( const json& value ) {
|
||||
if ( value.is_null() || value.empty() || !value.is_object() ) {
|
||||
template <typename T>
|
||||
std::optional<T> parseOptionalObject( const json& value, const std::string_view& name ) {
|
||||
if ( !value.contains( name ) || value[name].is_null() || value[name].empty() ||
|
||||
!value[name].is_object() ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return T( value );
|
||||
return T( value[name] );
|
||||
}
|
||||
|
||||
std::optional<std::unordered_map<std::string, std::string>>
|
||||
parseOptionalStringMap( const json& value ) {
|
||||
if ( value.is_null() || value.empty() || !value.is_object() ) {
|
||||
parseOptionalStringMap( const json& value, const std::string_view& name ) {
|
||||
if ( !value.contains( name ) || value[name].is_null() || value[name].empty() ||
|
||||
!value[name].is_object() ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto& dict = value;
|
||||
const auto& dict = value[name];
|
||||
std::unordered_map<std::string, std::string> map;
|
||||
for ( auto it = dict.begin(); it != dict.end(); ++it ) {
|
||||
map[it.key()] = it.value().get<std::string>();
|
||||
@@ -56,12 +62,14 @@ template <typename T> std::vector<T> parseObjectList( const json& array ) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::optional<std::vector<int>> parseOptionalIntList( const json& value ) {
|
||||
if ( value.is_null() || value.empty() || !value.is_array() ) {
|
||||
std::optional<std::vector<int>> parseOptionalIntList( const json& value,
|
||||
const std::string_view& name ) {
|
||||
if ( !value.contains( name ) || value[name].is_null() || value[name].empty() ||
|
||||
!value[name].is_array() ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::vector<int> values;
|
||||
for ( const auto& item : value ) {
|
||||
for ( const auto& item : value[name] ) {
|
||||
values.push_back( item.get<int>() );
|
||||
}
|
||||
return values;
|
||||
@@ -80,19 +88,19 @@ namespace ecode::dap {
|
||||
Message::Message( const json& body ) :
|
||||
id( body[DAP_ID].get<int>() ),
|
||||
format( body["format"].get<std::string>() ),
|
||||
variables( parseOptionalStringMap( body["variables"] ) ),
|
||||
sendTelemetry( parseOptionalBool( body["sendTelemetry"] ) ),
|
||||
showUser( parseOptionalBool( body["showUser"] ) ),
|
||||
url( parseOptionalString( body["url"] ) ),
|
||||
urlLabel( parseOptionalString( body["urlLabel"] ) ) {}
|
||||
variables( parseOptionalStringMap( body, "variables" ) ),
|
||||
sendTelemetry( parseOptionalBool( body, "sendTelemetry" ) ),
|
||||
showUser( parseOptionalBool( body, "showUser" ) ),
|
||||
url( parseOptionalString( body, "url" ) ),
|
||||
urlLabel( parseOptionalString( body, "urlLabel" ) ) {}
|
||||
|
||||
Response::Response( const json& msg ) :
|
||||
request_seq( msg.value( "request_seq", -1 ) ),
|
||||
success( msg.value( "success", false ) ),
|
||||
command( msg.value( DAP_COMMAND, "" ) ),
|
||||
message( msg.value( "message", "" ) ),
|
||||
body( msg[DAP_BODY] ),
|
||||
errorBody( success ? std::nullopt : parseOptionalObject<Message>( body["error"] ) ) {}
|
||||
body( msg.contains( DAP_BODY ) ? msg[DAP_BODY] : nlohmann::json{} ),
|
||||
errorBody( success ? std::nullopt : parseOptionalObject<Message>( body, "error" ) ) {}
|
||||
|
||||
bool Response::isCancelled() const {
|
||||
return message == "cancelled";
|
||||
@@ -100,20 +108,20 @@ bool Response::isCancelled() const {
|
||||
|
||||
ProcessInfo::ProcessInfo( const json& body ) :
|
||||
name( body.value( DAP_NAME, "" ) ),
|
||||
systemProcessId( parseOptionalInt( body[DAP_SYSTEM_PROCESS_ID] ) ),
|
||||
isLocalProcess( parseOptionalBool( body[DAP_IS_LOCAL_PROCESS] ) ),
|
||||
startMethod( parseOptionalString( body[DAP_START_METHOD] ) ),
|
||||
pointerSize( parseOptionalInt( body[DAP_POINTER_SIZE] ) ) {}
|
||||
systemProcessId( parseOptionalInt( body, DAP_SYSTEM_PROCESS_ID ) ),
|
||||
isLocalProcess( parseOptionalBool( body, DAP_IS_LOCAL_PROCESS ) ),
|
||||
startMethod( parseOptionalString( body, DAP_START_METHOD ) ),
|
||||
pointerSize( parseOptionalInt( body, DAP_POINTER_SIZE ) ) {}
|
||||
|
||||
Output::Output( const json& body ) :
|
||||
category( Category::Unknown ),
|
||||
output( body.value( DAP_OUTPUT, "" ) ),
|
||||
group( std::nullopt ),
|
||||
variablesReference( parseOptionalInt( body[DAP_VARIABLES_REFERENCE] ) ),
|
||||
source( parseOptionalObject<Source>( DAP_SOURCE ) ),
|
||||
line( parseOptionalInt( body[DAP_LINE] ) ),
|
||||
column( parseOptionalInt( body[DAP_COLUMN] ) ),
|
||||
data( body[DAP_DATA] ) {
|
||||
variablesReference( parseOptionalInt( body, DAP_VARIABLES_REFERENCE ) ),
|
||||
source( parseOptionalObject<Source>( body, DAP_SOURCE ) ),
|
||||
line( parseOptionalInt( body, DAP_LINE ) ),
|
||||
column( parseOptionalInt( body, DAP_COLUMN ) ),
|
||||
data( body.contains( DAP_DATA ) ? body[DAP_DATA] : nlohmann::json{} ) {
|
||||
if ( body.contains( DAP_GROUP ) ) {
|
||||
const auto value = body[DAP_GROUP].get<std::string>();
|
||||
if ( DAP_START == value ) {
|
||||
@@ -159,12 +167,12 @@ std::string Source::getUnifiedId( const std::string& path, std::optional<int> so
|
||||
}
|
||||
|
||||
Source::Source( const json& body ) :
|
||||
name( body[DAP_NAME].get<std::string>() ),
|
||||
path( body[DAP_PATH].get<std::string>() ),
|
||||
sourceReference( parseOptionalInt( body[DAP_SOURCE_REFERENCE] ) ),
|
||||
presentationHint( parseOptionalString( body[DAP_PRESENTATION_HINT] ) ),
|
||||
origin( body[DAP_ORIGIN].get<std::string>() ),
|
||||
adapterData( body[DAP_ADAPTER_DATA] ) {
|
||||
name( body.value( DAP_NAME, "" ) ),
|
||||
path( body.value( DAP_PATH, "" ) ),
|
||||
sourceReference( parseOptionalInt( body, DAP_SOURCE_REFERENCE ) ),
|
||||
presentationHint( parseOptionalString( body, DAP_PRESENTATION_HINT ) ),
|
||||
origin( body.value( DAP_ORIGIN, "" ) ),
|
||||
adapterData( body.contains( DAP_ADAPTER_DATA ) ? body[DAP_ADAPTER_DATA] : nlohmann::json{} ) {
|
||||
// sources
|
||||
if ( body.contains( DAP_SOURCES ) ) {
|
||||
const auto values = body[DAP_SOURCES];
|
||||
@@ -225,27 +233,27 @@ json Checksum::toJson() const {
|
||||
}
|
||||
|
||||
Capabilities::Capabilities( const json& body ) :
|
||||
supportsConfigurationDoneRequest( body["supportsConfigurationDoneRequest"].get<bool>() ),
|
||||
supportsFunctionBreakpoints( body["supportsFunctionBreakpoints"].get<bool>() ),
|
||||
supportsConditionalBreakpoints( body["supportsConditionalBreakpoints"].get<bool>() ),
|
||||
supportsHitConditionalBreakpoints( body["supportsHitConditionalBreakpoints"].get<bool>() ),
|
||||
supportsLogPoints( body["supportsLogPoints"].get<bool>() ),
|
||||
supportsModulesRequest( body["supportsModulesRequest"].get<bool>() ),
|
||||
supportsTerminateRequest( body["supportsTerminateRequest"].get<bool>() ),
|
||||
supportTerminateDebuggee( body["supportTerminateDebuggee"].get<bool>() ),
|
||||
supportsGotoTargetsRequest( body["supportsGotoTargetsRequest"].get<bool>() ) {}
|
||||
supportsConfigurationDoneRequest( body.value( "supportsConfigurationDoneRequest", false ) ),
|
||||
supportsFunctionBreakpoints( body.value( "supportsFunctionBreakpoints", false ) ),
|
||||
supportsConditionalBreakpoints( body.value( "supportsConditionalBreakpoints", false ) ),
|
||||
supportsHitConditionalBreakpoints( body.value( "supportsHitConditionalBreakpoints", false ) ),
|
||||
supportsLogPoints( body.value( "supportsLogPoints", false ) ),
|
||||
supportsModulesRequest( body.value( "supportsModulesRequest", false ) ),
|
||||
supportsTerminateRequest( body.value( "supportsTerminateRequest", false ) ),
|
||||
supportTerminateDebuggee( body.value( "supportTerminateDebuggee", false ) ),
|
||||
supportsGotoTargetsRequest( body.value( "supportsGotoTargetsRequest", false ) ) {}
|
||||
|
||||
ThreadEvent::ThreadEvent( const json& body ) :
|
||||
reason( body[DAP_REASON].get<std::string>() ), threadId( body[DAP_THREAD_ID].get<int>() ) {}
|
||||
|
||||
StoppedEvent::StoppedEvent( const json& body ) :
|
||||
reason( body[DAP_REASON].get<std::string>() ),
|
||||
description( parseOptionalString( body["description"] ) ),
|
||||
description( parseOptionalString( body, "description" ) ),
|
||||
threadId( body[DAP_THREAD_ID].get<int>() ),
|
||||
preserveFocusHint( parseOptionalBool( body["preserveFocusHint"] ) ),
|
||||
text( parseOptionalString( body["text"] ) ),
|
||||
allThreadsStopped( parseOptionalBool( body["allThreadsStopped"] ) ),
|
||||
hitBreakpointsIds( parseOptionalIntList( body["hitBreakpointsIds"] ) ) {}
|
||||
preserveFocusHint( parseOptionalBool( body, "preserveFocusHint" ) ),
|
||||
text( parseOptionalString( body, "text" ) ),
|
||||
allThreadsStopped( parseOptionalBool( body, "allThreadsStopped" ) ),
|
||||
hitBreakpointsIds( parseOptionalIntList( body, "hitBreakpointsIds" ) ) {}
|
||||
|
||||
Thread::Thread( const json& body ) :
|
||||
id( body[DAP_ID].get<int>() ), name( body[DAP_NAME].get<std::string>() ) {}
|
||||
@@ -259,48 +267,48 @@ std::vector<Thread> Thread::parseList( const json& threads ) {
|
||||
StackFrame::StackFrame( const json& body ) :
|
||||
id( body[DAP_ID].get<int>() ),
|
||||
name( body[DAP_NAME].get<std::string>() ),
|
||||
source( parseOptionalObject<Source>( body[DAP_SOURCE] ) ),
|
||||
source( parseOptionalObject<Source>( body, DAP_SOURCE ) ),
|
||||
line( body[DAP_LINE].get<int>() ),
|
||||
column( body[DAP_COLUMN].get<int>() ),
|
||||
endLine( parseOptionalInt( body["endLine"] ) ),
|
||||
canRestart( parseOptionalBool( ( body["canRestart"] ) ) ),
|
||||
instructionPointerReference( parseOptionalString( body["instructionPointerReference"] ) ),
|
||||
moduleId_int( parseOptionalInt( body[DAP_MODULE_ID] ) ),
|
||||
moduleId_str( parseOptionalString( body[DAP_MODULE_ID] ) ),
|
||||
presentationHint( parseOptionalString( body[DAP_PRESENTATION_HINT] ) ) {}
|
||||
endLine( parseOptionalInt( body, "endLine" ) ),
|
||||
canRestart( parseOptionalBool( body, "canRestart" ) ),
|
||||
instructionPointerReference( parseOptionalString( body, "instructionPointerReference" ) ),
|
||||
moduleId_int( parseOptionalInt( body, DAP_MODULE_ID ) ),
|
||||
moduleId_str( parseOptionalString( body, DAP_MODULE_ID ) ),
|
||||
presentationHint( parseOptionalString( body, DAP_PRESENTATION_HINT ) ) {}
|
||||
|
||||
StackTraceInfo::StackTraceInfo( const json& body ) :
|
||||
stackFrames( parseObjectList<StackFrame>( body["stackFrames"] ) ),
|
||||
totalFrames( parseOptionalInt( body["totalFrames"] ) ) {}
|
||||
totalFrames( parseOptionalInt( body, "totalFrames" ) ) {}
|
||||
|
||||
Module::Module( const json& body ) :
|
||||
id_int( parseOptionalInt( body[DAP_ID] ) ),
|
||||
id_str( parseOptionalString( body[DAP_ID] ) ),
|
||||
id_int( parseOptionalInt( body, DAP_ID ) ),
|
||||
id_str( parseOptionalString( body, DAP_ID ) ),
|
||||
name( body[DAP_NAME].get<std::string>() ),
|
||||
path( parseOptionalString( body[DAP_PATH] ) ),
|
||||
isOptimized( parseOptionalBool( body["isOptimized"] ) ),
|
||||
isUserCode( parseOptionalBool( body["isUserCode"] ) ),
|
||||
version( parseOptionalString( body["version"] ) ),
|
||||
symbolStatus( parseOptionalString( body["symbolStatus"] ) ),
|
||||
symbolFilePath( parseOptionalString( body["symbolFilePath"] ) ),
|
||||
dateTimeStamp( parseOptionalString( body["dateTimeStamp"] ) ),
|
||||
addressRange( parseOptionalString( body["addressRange"] ) ) {}
|
||||
path( parseOptionalString( body, DAP_PATH ) ),
|
||||
isOptimized( parseOptionalBool( body, "isOptimized" ) ),
|
||||
isUserCode( parseOptionalBool( body, "isUserCode" ) ),
|
||||
version( parseOptionalString( body, "version" ) ),
|
||||
symbolStatus( parseOptionalString( body, "symbolStatus" ) ),
|
||||
symbolFilePath( parseOptionalString( body, "symbolFilePath" ) ),
|
||||
dateTimeStamp( parseOptionalString( body, "dateTimeStamp" ) ),
|
||||
addressRange( parseOptionalString( body, "addressRange" ) ) {}
|
||||
|
||||
ModuleEvent::ModuleEvent( const json& body ) :
|
||||
reason( body[DAP_REASON].get<std::string>() ), module( Module( body["module"] ) ) {}
|
||||
|
||||
Scope::Scope( const json& body ) :
|
||||
name( body[DAP_NAME].get<std::string>() ),
|
||||
presentationHint( parseOptionalString( body[DAP_PRESENTATION_HINT] ) ),
|
||||
presentationHint( parseOptionalString( body, DAP_PRESENTATION_HINT ) ),
|
||||
variablesReference( body[DAP_VARIABLES_REFERENCE].get<int>() ),
|
||||
namedVariables( parseOptionalInt( body["namedVariables"] ) ),
|
||||
indexedVariables( parseOptionalInt( body["indexedVariables"] ) ),
|
||||
expensive( parseOptionalBool( body["expensive"] ) ),
|
||||
source( parseOptionalObject<Source>( body["source"] ) ),
|
||||
line( parseOptionalInt( body["line"] ) ),
|
||||
column( parseOptionalInt( body["column"] ) ),
|
||||
endLine( parseOptionalInt( body["endLine"] ) ),
|
||||
endColumn( parseOptionalInt( body["endColumn"] ) ) {}
|
||||
namedVariables( parseOptionalInt( body, "namedVariables" ) ),
|
||||
indexedVariables( parseOptionalInt( body, "indexedVariables" ) ),
|
||||
expensive( parseOptionalBool( body, "expensive" ) ),
|
||||
source( parseOptionalObject<Source>( body, "source" ) ),
|
||||
line( parseOptionalInt( body, "line" ) ),
|
||||
column( parseOptionalInt( body, "column" ) ),
|
||||
endLine( parseOptionalInt( body, "endLine" ) ),
|
||||
endColumn( parseOptionalInt( body, "endColumn" ) ) {}
|
||||
|
||||
Scope::Scope( int variablesReference, std::string name ) :
|
||||
name( name ), variablesReference( variablesReference ) {}
|
||||
@@ -312,12 +320,12 @@ std::vector<Scope> Scope::parseList( const json& scopes ) {
|
||||
Variable::Variable( const json& body ) :
|
||||
name( body[DAP_NAME].get<std::string>() ),
|
||||
value( body["value"].get<std::string>() ),
|
||||
type( parseOptionalString( body[DAP_TYPE].get<std::string>() ) ),
|
||||
evaluateName( parseOptionalString( body["evaluateName"].get<std::string>() ) ),
|
||||
type( parseOptionalString( body, DAP_TYPE ) ),
|
||||
evaluateName( parseOptionalString( body, "evaluateName" ) ),
|
||||
variablesReference( body[DAP_VARIABLES_REFERENCE].get<int>() ),
|
||||
namedVariables( parseOptionalInt( body["namedVariables"] ) ),
|
||||
indexedVariables( parseOptionalInt( body["indexedVariables"] ) ),
|
||||
memoryReference( parseOptionalString( body["memoryReference"] ) ) {}
|
||||
namedVariables( parseOptionalInt( body, "namedVariables" ) ),
|
||||
indexedVariables( parseOptionalInt( body, "indexedVariables" ) ),
|
||||
memoryReference( parseOptionalString( body, "memoryReference" ) ) {}
|
||||
|
||||
Variable::Variable( const std::string& name, const std::string& value, const int reference ) :
|
||||
name( name ), value( value ), variablesReference( reference ) {}
|
||||
@@ -328,18 +336,18 @@ std::vector<Variable> Variable::parseList( const json& variables ) {
|
||||
|
||||
ModulesInfo::ModulesInfo( const json& body ) :
|
||||
modules( parseObjectList<Module>( body[DAP_MODULES] ) ),
|
||||
totalModules( parseOptionalInt( body["totalModules"] ) ) {}
|
||||
totalModules( parseOptionalInt( body, "totalModules" ) ) {}
|
||||
|
||||
ContinuedEvent::ContinuedEvent( const json& body ) :
|
||||
threadId( body[DAP_THREAD_ID].get<int>() ),
|
||||
allThreadsContinued( parseOptionalBool( body[DAP_ALL_THREADS_CONTINUED] ) ) {}
|
||||
allThreadsContinued( parseOptionalBool( body, DAP_ALL_THREADS_CONTINUED ) ) {}
|
||||
|
||||
ContinuedEvent::ContinuedEvent( int threadId, bool allThreadsContinued ) :
|
||||
threadId( threadId ), allThreadsContinued( allThreadsContinued ) {}
|
||||
|
||||
SourceContent::SourceContent( const json& body ) :
|
||||
content( body["content"].get<std::string>() ),
|
||||
mimeType( parseOptionalString( body["mimeType"] ) ) {}
|
||||
mimeType( parseOptionalString( body, "mimeType" ) ) {}
|
||||
|
||||
SourceContent::SourceContent( const std::string& path ) {
|
||||
const FileInfo file( path );
|
||||
@@ -351,10 +359,10 @@ SourceContent::SourceContent( const std::string& path ) {
|
||||
|
||||
SourceBreakpoint::SourceBreakpoint( const json& body ) :
|
||||
line( body[DAP_LINE].get<int>() ),
|
||||
column( parseOptionalInt( body[DAP_COLUMN] ) ),
|
||||
condition( parseOptionalString( body[DAP_CONDITION] ) ),
|
||||
hitCondition( parseOptionalString( body[DAP_HIT_CONDITION] ) ),
|
||||
logMessage( parseOptionalString( body["logMessage"] ) ) {}
|
||||
column( parseOptionalInt( body, DAP_COLUMN ) ),
|
||||
condition( parseOptionalString( body, DAP_CONDITION ) ),
|
||||
hitCondition( parseOptionalString( body, DAP_HIT_CONDITION ) ),
|
||||
logMessage( parseOptionalString( body, "logMessage" ) ) {}
|
||||
|
||||
SourceBreakpoint::SourceBreakpoint( const int line ) : line( line ) {}
|
||||
|
||||
@@ -377,16 +385,16 @@ json SourceBreakpoint::toJson() const {
|
||||
}
|
||||
|
||||
Breakpoint::Breakpoint( const json& body ) :
|
||||
id( parseOptionalInt( body[DAP_ID] ) ),
|
||||
verified( body["verified"].get<bool>() ),
|
||||
message( parseOptionalString( body["message"] ) ),
|
||||
source( parseOptionalObject<Source>( body[DAP_SOURCE] ) ),
|
||||
line( parseOptionalInt( body[DAP_LINE] ) ),
|
||||
column( parseOptionalInt( body[DAP_COLUMN] ) ),
|
||||
endLine( parseOptionalInt( body[DAP_END_LINE] ) ),
|
||||
endColumn( parseOptionalInt( body[DAP_END_COLUMN] ) ),
|
||||
instructionReference( parseOptionalString( body["instructionReference"] ) ),
|
||||
offset( parseOptionalInt( body["offset"] ) ) {}
|
||||
id( parseOptionalInt( body, DAP_ID ) ),
|
||||
verified( body.value( "verified", false ) ),
|
||||
message( parseOptionalString( body, "message" ) ),
|
||||
source( parseOptionalObject<Source>( body, DAP_SOURCE ) ),
|
||||
line( parseOptionalInt( body, DAP_LINE ) ),
|
||||
column( parseOptionalInt( body, DAP_COLUMN ) ),
|
||||
endLine( parseOptionalInt( body, DAP_END_LINE ) ),
|
||||
endColumn( parseOptionalInt( body, DAP_END_COLUMN ) ),
|
||||
instructionReference( parseOptionalString( body, "instructionReference" ) ),
|
||||
offset( parseOptionalInt( body, "offset" ) ) {}
|
||||
|
||||
Breakpoint::Breakpoint( const int line ) : line( line ) {}
|
||||
|
||||
@@ -396,20 +404,20 @@ BreakpointEvent::BreakpointEvent( const json& body ) :
|
||||
|
||||
EvaluateInfo::EvaluateInfo( const json& body ) :
|
||||
result( body[DAP_RESULT].get<std::string>() ),
|
||||
type( parseOptionalString( body[DAP_TYPE] ) ),
|
||||
type( parseOptionalString( body, DAP_TYPE ) ),
|
||||
variablesReference( body[DAP_VARIABLES_REFERENCE].get<int>() ),
|
||||
namedVariables( parseOptionalInt( body["namedVariables"] ) ),
|
||||
indexedVariables( parseOptionalInt( body["indexedVariables"] ) ),
|
||||
memoryReference( parseOptionalString( body["memoryReference"] ) ) {}
|
||||
namedVariables( parseOptionalInt( body, "namedVariables" ) ),
|
||||
indexedVariables( parseOptionalInt( body, "indexedVariables" ) ),
|
||||
memoryReference( parseOptionalString( body, "memoryReference" ) ) {}
|
||||
|
||||
GotoTarget::GotoTarget( const json& body ) :
|
||||
id( body[DAP_ID].get<int>() ),
|
||||
label( body["label"].get<std::string>() ),
|
||||
line( body[DAP_LINE].get<int>() ),
|
||||
column( parseOptionalInt( body[DAP_COLUMN] ) ),
|
||||
endLine( parseOptionalInt( body[DAP_END_LINE] ) ),
|
||||
endColumn( parseOptionalInt( body[DAP_END_COLUMN] ) ),
|
||||
instructionPointerReference( parseOptionalString( body["instructionPointerReference"] ) ) {}
|
||||
column( parseOptionalInt( body, DAP_COLUMN ) ),
|
||||
endLine( parseOptionalInt( body, DAP_END_LINE ) ),
|
||||
endColumn( parseOptionalInt( body, DAP_END_COLUMN ) ),
|
||||
instructionPointerReference( parseOptionalString( body, "instructionPointerReference" ) ) {}
|
||||
|
||||
std::vector<GotoTarget> GotoTarget::parseList( const json& variables ) {
|
||||
return parseObjectList<GotoTarget>( variables );
|
||||
|
||||
@@ -19,7 +19,7 @@ void DebuggerClient::debuggeeRunning() {
|
||||
|
||||
void DebuggerClient::debuggeeTerminated() {
|
||||
for ( auto listener : mListeners )
|
||||
listener->debuggeeRunning();
|
||||
listener->debuggeeTerminated();
|
||||
}
|
||||
|
||||
void DebuggerClient::failed() {
|
||||
|
||||
@@ -15,6 +15,7 @@ class DebuggerClient {
|
||||
virtual void stateChanged( State ) = 0;
|
||||
virtual void initialized() = 0;
|
||||
virtual void launched() = 0;
|
||||
virtual void configured() = 0;
|
||||
virtual void failed() = 0;
|
||||
virtual void debuggeeRunning() = 0;
|
||||
virtual void debuggeeTerminated() = 0;
|
||||
@@ -69,14 +70,14 @@ class DebuggerClient {
|
||||
|
||||
virtual bool threads() = 0;
|
||||
|
||||
virtual bool stackTrace( int threadId, int startFrame, int levels ) = 0;
|
||||
virtual bool stackTrace( int threadId, int startFrame = 0, int levels = 0 ) = 0;
|
||||
|
||||
virtual bool scopes( int frameId ) = 0;
|
||||
|
||||
virtual bool modules( int start, int count ) = 0;
|
||||
|
||||
virtual bool variables( int variablesReference, Variable::Type filter, int start,
|
||||
int count ) = 0;
|
||||
virtual bool variables( int variablesReference, Variable::Type filter = Variable::Type::Both,
|
||||
int start = 0, int count = 0 ) = 0;
|
||||
|
||||
virtual bool evaluate( const std::string& expression, const std::string& context,
|
||||
std::optional<int> frameId ) = 0;
|
||||
@@ -101,10 +102,14 @@ class DebuggerClient {
|
||||
|
||||
virtual bool watch( const std::string& expression, std::optional<int> frameId ) = 0;
|
||||
|
||||
virtual bool configurationDone() = 0;
|
||||
|
||||
void addListener( Listener* listener );
|
||||
|
||||
void removeListener( Listener* listener );
|
||||
|
||||
virtual ~DebuggerClient() {}
|
||||
|
||||
protected:
|
||||
void setState( const State& state );
|
||||
|
||||
|
||||
@@ -1,24 +1,42 @@
|
||||
#include "debuggerclientlistener.hpp"
|
||||
#include "debuggerplugin.hpp"
|
||||
|
||||
namespace ecode {
|
||||
|
||||
DebuggerClientListener::DebuggerClientListener( DebuggerClient* client, DebuggerPlugin* plugin ) :
|
||||
mClient( client ), mPlugin( plugin ) {
|
||||
eeASSERT( mClient && mPlugin );
|
||||
}
|
||||
|
||||
void DebuggerClientListener::stateChanged( DebuggerClient::State ) {}
|
||||
|
||||
void DebuggerClientListener::initialized() {}
|
||||
void DebuggerClientListener::initialized() {
|
||||
// mClient->setBreakpoints( "/home/programming/eepp/src/tools/ecode/ecode.cpp",
|
||||
// { SourceBreakpoint( 4116 ) } );
|
||||
}
|
||||
|
||||
void DebuggerClientListener::launched() {}
|
||||
|
||||
void DebuggerClientListener::configured() {}
|
||||
|
||||
void DebuggerClientListener::failed() {}
|
||||
|
||||
void DebuggerClientListener::debuggeeRunning() {}
|
||||
|
||||
void DebuggerClientListener::debuggeeTerminated() {}
|
||||
|
||||
void DebuggerClientListener::capabilitiesReceived( const Capabilities& capabilities ) {}
|
||||
void DebuggerClientListener::capabilitiesReceived( const Capabilities& /*capabilities*/ ) {}
|
||||
|
||||
void DebuggerClientListener::debuggeeExited( int exitCode ) {}
|
||||
void DebuggerClientListener::debuggeeExited( int /*exitCode*/ ) {
|
||||
mPlugin->exitDebugger();
|
||||
}
|
||||
|
||||
void DebuggerClientListener::debuggeeStopped( const StoppedEvent& ) {}
|
||||
void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) {
|
||||
Log::warning( "DebuggerClientListener::debuggeeStopped: reason %s", event.reason );
|
||||
// if ( event.threadId ) {
|
||||
// mClient->stackTrace( *event.threadId );
|
||||
// }
|
||||
}
|
||||
|
||||
void DebuggerClientListener::debuggeeContinued( const ContinuedEvent& ) {}
|
||||
|
||||
@@ -26,39 +44,50 @@ void DebuggerClientListener::outputProduced( const Output& ) {}
|
||||
|
||||
void DebuggerClientListener::debuggingProcess( const ProcessInfo& ) {}
|
||||
|
||||
void DebuggerClientListener::errorResponse( const std::string& summary,
|
||||
const std::optional<Message>& message ) {}
|
||||
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>& ) {}
|
||||
void DebuggerClientListener::threads( const std::vector<Thread>& /*threads*/ ) {}
|
||||
|
||||
void DebuggerClientListener::stackTrace( const int threadId, const StackTraceInfo& ) {}
|
||||
void DebuggerClientListener::stackTrace( const int /*threadId*/, const StackTraceInfo& stack ) {
|
||||
// if ( !stack.stackFrames.empty() ) {
|
||||
// mClient->scopes( stack.stackFrames[0].id );
|
||||
// }
|
||||
}
|
||||
|
||||
void DebuggerClientListener::scopes( const int frameId, const std::vector<Scope>& ) {}
|
||||
void DebuggerClientListener::scopes( const int /*frameId**/, const std::vector<Scope>& scopes ) {
|
||||
// if ( !scopes.empty() ) {
|
||||
// mClient->variables( scopes[0].variablesReference );
|
||||
// }
|
||||
}
|
||||
|
||||
void DebuggerClientListener::variables( const int variablesReference,
|
||||
const std::vector<Variable>& ) {}
|
||||
void DebuggerClientListener::variables( const int /*variablesReference*/,
|
||||
const std::vector<Variable>& vars ) {
|
||||
// if ( !vars.empty() ) {
|
||||
// mClient->resume( 1 );
|
||||
// }
|
||||
}
|
||||
|
||||
void DebuggerClientListener::modules( const ModulesInfo& ) {}
|
||||
|
||||
void DebuggerClientListener::serverDisconnected() {}
|
||||
|
||||
void DebuggerClientListener::sourceContent( const std::string& path, int reference,
|
||||
const SourceContent& content ) {}
|
||||
void DebuggerClientListener::sourceContent( const std::string& /*path*/, int /*reference*/,
|
||||
const SourceContent& /*content*/ ) {}
|
||||
|
||||
void DebuggerClientListener::sourceBreakpoints(
|
||||
const std::string& path, int reference,
|
||||
const std::optional<std::vector<Breakpoint>>& breakpoints ) {}
|
||||
const std::string& /*path*/, int /*reference*/,
|
||||
const std::optional<std::vector<Breakpoint>>& /*breakpoints*/ ) {}
|
||||
|
||||
void DebuggerClientListener::breakpointChanged( const BreakpointEvent& ) {}
|
||||
|
||||
void DebuggerClientListener::expressionEvaluated( const std::string& expression,
|
||||
void DebuggerClientListener::expressionEvaluated( const std::string& /*expression*/,
|
||||
const std::optional<EvaluateInfo>& ) {}
|
||||
void DebuggerClientListener::gotoTargets( const Source& source, const int line,
|
||||
|
||||
const std::vector<GotoTarget>& targets ) {}
|
||||
void DebuggerClientListener::gotoTargets( const Source& /*source*/, const int /*line*/,
|
||||
const std::vector<GotoTarget>& /*targets*/ ) {}
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -3,11 +3,16 @@
|
||||
|
||||
namespace ecode {
|
||||
|
||||
class DebuggerPlugin;
|
||||
|
||||
class DebuggerClientListener : public DebuggerClient::Listener {
|
||||
public:
|
||||
DebuggerClientListener( DebuggerClient* client, DebuggerPlugin* plugin );
|
||||
|
||||
void stateChanged( DebuggerClient::State );
|
||||
void initialized();
|
||||
void launched();
|
||||
void configured();
|
||||
void failed();
|
||||
void debuggeeRunning();
|
||||
void debuggeeTerminated();
|
||||
@@ -27,13 +32,18 @@ class DebuggerClientListener : public DebuggerClient::Listener {
|
||||
void variables( const int variablesReference, const std::vector<Variable>& );
|
||||
void modules( const ModulesInfo& );
|
||||
void serverDisconnected();
|
||||
void sourceContent( const std::string& path, int reference, const SourceContent& content = SourceContent() );
|
||||
void sourceBreakpoints( const std::string& path, int reference, const std::optional<std::vector<Breakpoint>>& breakpoints );
|
||||
void sourceContent( const std::string& path, int reference,
|
||||
const SourceContent& content = SourceContent() );
|
||||
void sourceBreakpoints( const std::string& path, int reference,
|
||||
const std::optional<std::vector<Breakpoint>>& breakpoints );
|
||||
void breakpointChanged( const BreakpointEvent& );
|
||||
void expressionEvaluated( const std::string& expression, const std::optional<EvaluateInfo>& );
|
||||
void gotoTargets( const Source& source, const int line, const std::vector<GotoTarget>& targets );
|
||||
void gotoTargets( const Source& source, const int line,
|
||||
const std::vector<GotoTarget>& targets );
|
||||
|
||||
protected:
|
||||
DebuggerClient* mClient{ nullptr };
|
||||
DebuggerPlugin* mPlugin{ nullptr };
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "debuggerplugin.hpp"
|
||||
#include "../../projectbuild.hpp"
|
||||
#include "busprocess.hpp"
|
||||
#include "dap/debuggerclientdap.hpp"
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
@@ -48,6 +49,9 @@ DebuggerPlugin::~DebuggerPlugin() {
|
||||
|
||||
if ( mSidePanel && mTab )
|
||||
mSidePanel->removeTab( mTab );
|
||||
|
||||
mDebugger.reset();
|
||||
mListener.reset();
|
||||
}
|
||||
|
||||
void DebuggerPlugin::load( PluginManager* pluginManager ) {
|
||||
@@ -256,10 +260,10 @@ void DebuggerPlugin::updateSidePanelTab() {
|
||||
|
||||
updateDebuggerConfigurationList();
|
||||
|
||||
UIPushButton* runButton = mTabContents->find<UIPushButton>( "run_button" );
|
||||
mRunButton = mTabContents->find<UIPushButton>( "run_button" );
|
||||
|
||||
if ( !runButton->hasEventsOfType( Event::MouseClick ) ) {
|
||||
runButton->onClick( [this]( auto ) {
|
||||
if ( !mRunButton->hasEventsOfType( Event::MouseClick ) ) {
|
||||
mRunButton->onClick( [this]( auto ) {
|
||||
runConfig( mUIDebuggerList->getListBox()->getItemSelectedText().toUtf8(),
|
||||
mUIDebuggerConfList->getListBox()->getItemSelectedText().toUtf8() );
|
||||
} );
|
||||
@@ -293,6 +297,38 @@ void DebuggerPlugin::updateDebuggerConfigurationList() {
|
||||
mUIDebuggerConfList->getListBox()->setSelected( 0L );
|
||||
}
|
||||
|
||||
void DebuggerPlugin::replaceKeysInJson( nlohmann::json& json ) {
|
||||
static constexpr auto KEY_FILE = "${file}";
|
||||
static constexpr auto KEY_ARGS = "${args}";
|
||||
static constexpr auto KEY_CWD = "${cwd}";
|
||||
static constexpr auto KEY_ENV = "${env}";
|
||||
static constexpr auto KEY_STOPONENTRY = "${stopOnEntry}";
|
||||
auto runConfig = getManager()->getProjectBuildManager()->getCurrentRunConfig();
|
||||
|
||||
for ( auto& j : json ) {
|
||||
if ( j.is_object() ) {
|
||||
replaceKeysInJson( j );
|
||||
} else if ( j.is_string() ) {
|
||||
std::string val( j.get<std::string>() );
|
||||
if ( runConfig && !runConfig->cmd.empty() && val == KEY_FILE ) {
|
||||
j = runConfig->cmd;
|
||||
} else if ( runConfig && !runConfig->args.empty() && val == KEY_ARGS ) {
|
||||
auto argsArr = nlohmann::json::array();
|
||||
auto args = Process::parseArgs( runConfig->args );
|
||||
for ( const auto& arg : args )
|
||||
argsArr.push_back( arg );
|
||||
j = argsArr;
|
||||
} else if ( runConfig && val == KEY_CWD ) {
|
||||
j = runConfig->workingDir;
|
||||
} else if ( runConfig && val == KEY_ENV ) {
|
||||
j = nlohmann::json{};
|
||||
} else if ( val == KEY_STOPONENTRY ) {
|
||||
j = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerPlugin::runConfig( const std::string& debugger, const std::string& configuration ) {
|
||||
auto debuggerIt = std::find_if( mDaps.begin(), mDaps.end(), [&debugger]( const DapTool& dap ) {
|
||||
return dap.name == debugger;
|
||||
@@ -312,17 +348,41 @@ void DebuggerPlugin::runConfig( const std::string& debugger, const std::string&
|
||||
|
||||
ProtocolSettings protocolSettings;
|
||||
protocolSettings.launchCommand = configIt->command;
|
||||
protocolSettings.launchRequest = configIt->args;
|
||||
auto args = configIt->args;
|
||||
replaceKeysInJson( args );
|
||||
protocolSettings.launchRequest = args;
|
||||
|
||||
Command cmd;
|
||||
cmd.command = debuggerIt->run.command;
|
||||
cmd.arguments = debuggerIt->run.args;
|
||||
|
||||
auto bus = std::make_unique<BusProcess>( cmd );
|
||||
|
||||
mDebugger = std::make_unique<DebuggerClientDap>( protocolSettings, std::move( bus ) );
|
||||
mListener = std::make_unique<DebuggerClientListener>();
|
||||
mListener = std::make_unique<DebuggerClientListener>( mDebugger.get(), this );
|
||||
mDebugger->addListener( mListener.get() );
|
||||
mDebugger->start();
|
||||
|
||||
mRunButton->setEnabled( false );
|
||||
|
||||
mThreadPool->run(
|
||||
[this] { mDebugger->start(); },
|
||||
[this]( const Uint64& ) {
|
||||
if ( !mDebugger || mDebugger->state() != DebuggerClient::State::Running ) {
|
||||
mRunButton->runOnMainThread( [this] { mRunButton->setEnabled( false ); } );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void DebuggerPlugin::exitDebugger() {
|
||||
if ( mDebugger && mListener )
|
||||
mDebugger->removeListener( mListener.get() );
|
||||
mThreadPool->run( [this] {
|
||||
mDebugger.reset();
|
||||
mListener.reset();
|
||||
} );
|
||||
if ( getUISceneNode() ) {
|
||||
getUISceneNode()->runOnMainThread( [this] { mRunButton->setEnabled( true ); } );
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerPlugin::hideSidePanel() {
|
||||
|
||||
@@ -38,7 +38,7 @@ class DebuggerPlugin : public PluginBase {
|
||||
|
||||
static Plugin* NewSync( PluginManager* pluginManager );
|
||||
|
||||
~DebuggerPlugin();
|
||||
virtual ~DebuggerPlugin();
|
||||
|
||||
std::string getId() override { return Definition().id; }
|
||||
|
||||
@@ -47,6 +47,8 @@ class DebuggerPlugin : public PluginBase {
|
||||
std::string getDescription() override { return Definition().description; }
|
||||
|
||||
protected:
|
||||
friend class DebuggerClientListener;
|
||||
|
||||
std::vector<DapTool> mDaps;
|
||||
std::unique_ptr<DebuggerClient> mDebugger;
|
||||
std::unique_ptr<DebuggerClientListener> mListener;
|
||||
@@ -57,6 +59,7 @@ class DebuggerPlugin : public PluginBase {
|
||||
UIWidget* mTabContents{ nullptr };
|
||||
UIDropDownList* mUIDebuggerList{ nullptr };
|
||||
UIDropDownList* mUIDebuggerConfList{ nullptr };
|
||||
UIPushButton* mRunButton{ nullptr };
|
||||
|
||||
DebuggerPlugin( PluginManager* pluginManager, bool sync );
|
||||
|
||||
@@ -77,6 +80,10 @@ class DebuggerPlugin : public PluginBase {
|
||||
void loadDAPConfig( const std::string& path, bool updateConfigFile );
|
||||
|
||||
void runConfig( const std::string& debugger, const std::string& configuration );
|
||||
|
||||
void exitDebugger();
|
||||
|
||||
void replaceKeysInJson( nlohmann::json& json );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -767,7 +767,7 @@ void ProjectBuildManager::runCurrentConfig( StatusAppOutputController* saoc, boo
|
||||
}
|
||||
}
|
||||
|
||||
bool ProjectBuildManager::hasBuildConfig() {
|
||||
bool ProjectBuildManager::hasBuildConfig() const {
|
||||
return !getBuilds().empty() && !mConfig.buildName.empty();
|
||||
}
|
||||
|
||||
@@ -779,6 +779,20 @@ bool ProjectBuildManager::hasRunConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<ProjectBuildStep> ProjectBuildManager::getCurrentRunConfig() {
|
||||
if ( hasBuildConfig() ) {
|
||||
auto build = getBuild( mConfig.buildName );
|
||||
if ( build != nullptr && build->hasRun() ) {
|
||||
for ( const auto& crun : build->mRun ) {
|
||||
if ( crun->name == mConfig.runName || mConfig.runName.empty() ) {
|
||||
return build->replaceVars( *crun.get() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ProjectBuildManager::runConfig( StatusAppOutputController* saoc ) {
|
||||
if ( !isRunningApp() && !getBuilds().empty() ) {
|
||||
BoolScopedOp op( mRunning, true );
|
||||
|
||||
@@ -333,10 +333,12 @@ class ProjectBuildManager {
|
||||
|
||||
bool hasRunConfig();
|
||||
|
||||
bool hasBuildConfig();
|
||||
bool hasBuildConfig() const;
|
||||
|
||||
void selectTab();
|
||||
|
||||
std::optional<ProjectBuildStep> getCurrentRunConfig();
|
||||
|
||||
protected:
|
||||
std::string mProjectRoot;
|
||||
std::string mProjectFile;
|
||||
|
||||
Reference in New Issue
Block a user