mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-25 15:53:11 +03:00
Add DAP multi-session support and add Node.js debugging support.
This commit is contained in:
@@ -254,7 +254,7 @@
|
||||
"languages": ["javascript", "typescript"],
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Node.js program",
|
||||
"name": "Launch script",
|
||||
"request": "launch",
|
||||
"arguments": {
|
||||
"type": "pwa-node",
|
||||
@@ -263,7 +263,39 @@
|
||||
"cwd": "${cwd}",
|
||||
"env": "${env}",
|
||||
"runtimeExecutable": "node",
|
||||
"console": "externalConsole"
|
||||
"autoAttachChildProcesses": true,
|
||||
"enableDWARF":true,
|
||||
"enableContentValidation":true,
|
||||
"outputCapture":"console",
|
||||
"timeout":10000,
|
||||
"showAsyncStacks":true,
|
||||
"smartStep":true,
|
||||
"sourceMaps":true,
|
||||
"sourceMapRenames":true,
|
||||
"pauseForSourceMap":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Launch script in Terminal",
|
||||
"request": "launch",
|
||||
"arguments": {
|
||||
"type": "pwa-node",
|
||||
"program": "${file}",
|
||||
"args": "${args}",
|
||||
"cwd": "${cwd}",
|
||||
"env": "${env}",
|
||||
"runtimeExecutable": "node",
|
||||
"console": "externalConsole",
|
||||
"autoAttachChildProcesses": true,
|
||||
"enableDWARF":true,
|
||||
"enableContentValidation":true,
|
||||
"outputCapture":"console",
|
||||
"timeout":10000,
|
||||
"showAsyncStacks":true,
|
||||
"smartStep":true,
|
||||
"sourceMaps":true,
|
||||
"sourceMapRenames":true,
|
||||
"pauseForSourceMap":false
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 16.0.2, 2025-06-20T02:09:36. -->
|
||||
<!-- Written by QtCreator 16.0.2, 2025-06-22T01:07:13. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
@@ -1199,7 +1199,6 @@
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
|
||||
<value type="QString" key="RunConfiguration.Arguments">--text-shaper</value>
|
||||
<value type="int" key="RunConfiguration.UseCppDebugger">0</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
|
||||
<value type="int" key="RunConfiguration.UseQmlDebugger">1</value>
|
||||
|
||||
@@ -355,7 +355,8 @@ void TcpSocket::startAsyncRead( ReadFn readFn ) {
|
||||
while ( receive( buffer.data(), buffer.size(), received ) == Status::Done &&
|
||||
received > 0 )
|
||||
readFn( buffer.c_str(), received );
|
||||
if ( clock.getElapsedTime().asMilliseconds() < 100.f ) {
|
||||
if ( mSocket != Private::SocketImpl::invalidSocket() &&
|
||||
clock.getElapsedTime().asMilliseconds() < 100.f ) {
|
||||
auto ms = 100.f - clock.getElapsedTime().asMilliseconds();
|
||||
Sys::sleep( Milliseconds( ms ) );
|
||||
}
|
||||
|
||||
@@ -1204,8 +1204,9 @@ void App::loadFileFromPathOrFocus(
|
||||
}
|
||||
}
|
||||
|
||||
void App::focusOrLoadFile( const std::string& path, const TextRange& range ) {
|
||||
UITab* tab = mSplitter->isDocumentOpen( path, true );
|
||||
void App::focusOrLoadFile( const std::string& path, const TextRange& range,
|
||||
bool searchInSameContext ) {
|
||||
UITab* tab = mSplitter->isDocumentOpen( path, searchInSameContext );
|
||||
if ( !tab ) {
|
||||
FileInfo fileInfo( path );
|
||||
if ( fileInfo.exists() && fileInfo.isRegularFile() )
|
||||
|
||||
@@ -411,7 +411,8 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
|
||||
std::function<void( UICodeEditor*, const std::string& )> onLoaded =
|
||||
std::function<void( UICodeEditor*, const std::string& )>() );
|
||||
|
||||
void focusOrLoadFile( const std::string& path, const TextRange& range = {} );
|
||||
void focusOrLoadFile( const std::string& path, const TextRange& range = {},
|
||||
bool searchInSameContext = true );
|
||||
|
||||
UISceneNode* getUISceneNode() const { return mUISceneNode; }
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ class Bus {
|
||||
public:
|
||||
enum class State { None, Running, Closed };
|
||||
|
||||
enum class Type { Process, Socket, SocketProcess };
|
||||
|
||||
typedef std::function<void( const char* bytes, size_t n )> ReadFn;
|
||||
|
||||
State state() const;
|
||||
@@ -20,6 +22,8 @@ class Bus {
|
||||
|
||||
virtual size_t write( const char* buffer, const size_t& size ) = 0;
|
||||
|
||||
virtual Type type() const = 0;
|
||||
|
||||
virtual bool hasProcess() { return false; }
|
||||
|
||||
virtual ~Bus() {}
|
||||
|
||||
@@ -22,6 +22,10 @@ class BusProcess : public Bus {
|
||||
|
||||
bool hasProcess() override { return true; }
|
||||
|
||||
Type type() const override { return Bus::Type::Process; }
|
||||
|
||||
const Command& getCommand() const { return mCommand; }
|
||||
|
||||
protected:
|
||||
Command mCommand;
|
||||
Process mProcess;
|
||||
|
||||
@@ -22,6 +22,10 @@ class BusSocket : public Bus {
|
||||
|
||||
bool hasProcess() override { return false; }
|
||||
|
||||
Type type() const override { return Bus::Type::Socket; }
|
||||
|
||||
const Connection& getConnection() const { return mConnection; }
|
||||
|
||||
protected:
|
||||
Connection mConnection;
|
||||
TcpSocket mSocket;
|
||||
|
||||
@@ -22,6 +22,12 @@ class BusSocketProcess : public Bus {
|
||||
|
||||
bool hasProcess() override { return true; }
|
||||
|
||||
Type type() const override { return Bus::Type::SocketProcess; }
|
||||
|
||||
const Command& getCommand() const { return mCommand; }
|
||||
|
||||
const Connection& getConnection() const { return mConnection; }
|
||||
|
||||
protected:
|
||||
Command mCommand;
|
||||
Connection mConnection;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,10 @@
|
||||
#include <atomic>
|
||||
#include <eepp/config.hpp>
|
||||
#include <eepp/core.hpp>
|
||||
#include <eepp/system/mutex.hpp>
|
||||
|
||||
using namespace EE;
|
||||
using namespace EE::System;
|
||||
|
||||
namespace ecode::dap {
|
||||
|
||||
@@ -45,11 +47,9 @@ class DebuggerClientDap : public DebuggerClient {
|
||||
bool terminate( bool restart ) override;
|
||||
|
||||
bool disconnect( bool terminateDebuggee, bool restart = false ) override;
|
||||
|
||||
bool threads() override;
|
||||
|
||||
bool stackTrace( int threadId, int startFrame = 0, int levels = 0 ) override;
|
||||
|
||||
bool scopes( int frameId ) override;
|
||||
|
||||
bool variables( int variablesReference, Variable::Type filter = Variable::Type::Both,
|
||||
@@ -58,10 +58,10 @@ class DebuggerClientDap : public DebuggerClient {
|
||||
|
||||
bool modules( int start, int count ) override;
|
||||
|
||||
bool evaluate(
|
||||
const std::string& expression, const std::string& context, std::optional<int> frameId,
|
||||
std::function<void( const std::string& expression, const std::optional<EvaluateInfo>& )>
|
||||
cb = {} ) override;
|
||||
bool evaluate( const std::string& expression, const std::string& context,
|
||||
std::optional<int> frameId,
|
||||
std::function<void( const std::string&, const std::optional<EvaluateInfo>& )>
|
||||
cb = {} ) override;
|
||||
|
||||
bool isServerConnected() const override;
|
||||
|
||||
@@ -78,89 +78,102 @@ class DebuggerClientDap : public DebuggerClient {
|
||||
bool sourceModified = false ) override;
|
||||
|
||||
bool gotoTargets( const std::string& path, const int line,
|
||||
const std::optional<int> column = std::nullopt ) override;
|
||||
|
||||
const std::optional<int> column = std::nullopt ) override;
|
||||
bool gotoTargets( const dap::Source& source, const int line,
|
||||
|
||||
const std::optional<int> column = std::nullopt ) override;
|
||||
|
||||
bool watch( const std::string& expression, std::optional<int> frameId ) override;
|
||||
|
||||
bool configurationDone() override;
|
||||
bool configurationDone( const SessionId& sessionId ) override;
|
||||
|
||||
bool started() const override;
|
||||
|
||||
void setSilent( bool silent ) override { mDebug = !silent; }
|
||||
|
||||
size_t sessionsActive() override { return mSessions.size(); }
|
||||
|
||||
protected:
|
||||
std::unique_ptr<Bus> mBus;
|
||||
UnorderedMap<std::string, UnorderedSet<int>> mBreakpoints;
|
||||
std::atomic<Uint64> mIdx{ 1 };
|
||||
Uint64 mThreadId{ 1 };
|
||||
bool mDebug{ true };
|
||||
bool mStarted{ false };
|
||||
// Session structure to hold per-session data
|
||||
struct Session {
|
||||
State state = State::None;
|
||||
std::string launchRequestType;
|
||||
nlohmann::json launchArgs;
|
||||
bool launched = false;
|
||||
bool configured = false;
|
||||
bool waitingToAttach = false;
|
||||
std::unique_ptr<Bus> bus;
|
||||
std::atomic<Uint64> idx{ 1 };
|
||||
};
|
||||
|
||||
struct Request {
|
||||
std::string command;
|
||||
nlohmann::json arguments;
|
||||
ResponseHandler handler;
|
||||
std::string sessionId; // Associate request with a session
|
||||
};
|
||||
|
||||
UnorderedMap<std::string, UnorderedSet<int>> mBreakpoints;
|
||||
bool mDebug{ true };
|
||||
bool mStarted{ false };
|
||||
bool mDestroying{ false };
|
||||
std::unordered_map<Uint64, Request> mRequests;
|
||||
std::string mBuffer;
|
||||
ProtocolSettings mProtocol;
|
||||
Capabilities mAdapterCapabilities;
|
||||
std::vector<std::unique_ptr<Bus>> mBusesToClose;
|
||||
|
||||
// Session management
|
||||
mutable Mutex mSessionsMutex;
|
||||
std::unordered_map<std::string, Session> mSessions; // Session ID to Session
|
||||
std::string mCurrentSessionId; // Latest active session
|
||||
std::unordered_map<int, std::string> mThreadToSession; // Thread ID to Session ID
|
||||
|
||||
void setState( const State& state, const SessionId& sessionId ) override;
|
||||
|
||||
void checkRunning( const SessionId& sessionId ) override;
|
||||
|
||||
void makeRequest( const std::string_view& command, const nlohmann::json& arguments,
|
||||
ResponseHandler onFinish = nullptr );
|
||||
|
||||
ResponseHandler onFinish, const SessionId& sessionId );
|
||||
void makeResponse( int reqSeq, bool success, const std::string& command,
|
||||
const nlohmann::json& body );
|
||||
|
||||
const nlohmann::json& body, const std::string& sessionId );
|
||||
void asyncRead( const char* bytes, size_t n );
|
||||
|
||||
void processProtocolMessage( const nlohmann::json& msg );
|
||||
|
||||
void processResponse( const nlohmann::json& msg );
|
||||
|
||||
void processEvent( const nlohmann::json& msg );
|
||||
|
||||
void processRequest( const nlohmann::json& msg );
|
||||
|
||||
struct HeaderInfo {
|
||||
Uint64 payloadStart;
|
||||
Uint64 payloadLength;
|
||||
};
|
||||
|
||||
std::optional<HeaderInfo> readHeader();
|
||||
|
||||
void errorResponse( const std::string& command, const std::string& summary,
|
||||
const std::optional<Message>& message );
|
||||
const std::optional<Message>& message, const SessionId& sessionId = "" );
|
||||
|
||||
void processEventInitialized();
|
||||
// Event handlers
|
||||
void processEventInitialized( const SessionId& sessionId );
|
||||
void processEventTerminated( const SessionId& sessionId );
|
||||
void processEventExited( const nlohmann::json& body, const SessionId& sessionId );
|
||||
void processEventOutput( const nlohmann::json& body, const SessionId& sessionId );
|
||||
void processEventProcess( const nlohmann::json& body, const SessionId& sessionId );
|
||||
void processEventThread( const nlohmann::json& body, const SessionId& sessionId );
|
||||
void processEventStopped( const nlohmann::json& body, const SessionId& sessionId );
|
||||
void processEventModule( const nlohmann::json& body, const SessionId& sessionId );
|
||||
void processEventContinued( const nlohmann::json& body, const SessionId& sessionId );
|
||||
void processEventBreakpoint( const nlohmann::json& body, const SessionId& sessionId );
|
||||
|
||||
void processEventTerminated();
|
||||
// Session-specific methods
|
||||
void requestInitialize( const SessionId& sessionId, std::function<void()> onLaunch = {} );
|
||||
void requestLaunchCommand( const SessionId& sessionId, std::function<void()> onLaunch = {} );
|
||||
void processResponseInitialize( const Response& response, const nlohmann::json&,
|
||||
const SessionId& sessionId,
|
||||
std::function<void()> onLaunch = {} );
|
||||
void processResponseNext( const Response& response, const nlohmann::json& request,
|
||||
const SessionId& sessionId );
|
||||
|
||||
void processEventExited( const nlohmann::json& body );
|
||||
|
||||
void processEventOutput( const nlohmann::json& body );
|
||||
|
||||
void processEventProcess( const nlohmann::json& body );
|
||||
|
||||
void processEventThread( const nlohmann::json& body );
|
||||
|
||||
void processEventStopped( const nlohmann::json& body );
|
||||
|
||||
void processEventModule( const nlohmann::json& body );
|
||||
|
||||
void processEventContinued( const nlohmann::json& body );
|
||||
|
||||
void processEventBreakpoint( const nlohmann::json& body );
|
||||
|
||||
void requestInitialize();
|
||||
|
||||
void requestLaunchCommand( std::function<void()> onLaunch = {} );
|
||||
|
||||
void processResponseInitialize( const Response& response, const nlohmann::json& );
|
||||
|
||||
void processResponseNext( const Response& response, const nlohmann::json& request );
|
||||
// Helper to find session by thread ID
|
||||
std::string findSessionByThread( int threadId ) const;
|
||||
};
|
||||
|
||||
} // namespace ecode::dap
|
||||
|
||||
@@ -2,59 +2,29 @@
|
||||
|
||||
namespace ecode {
|
||||
|
||||
void DebuggerClient::stateChanged( State state ) {
|
||||
void DebuggerClient::stateChanged( State state, const SessionId& sessionId ) {
|
||||
for ( auto listener : mListeners )
|
||||
listener->stateChanged( state );
|
||||
listener->stateChanged( state, sessionId );
|
||||
}
|
||||
|
||||
void DebuggerClient::initialized() {
|
||||
void DebuggerClient::initialized( const SessionId& sessionId ) {
|
||||
for ( auto listener : mListeners )
|
||||
listener->initialized();
|
||||
listener->initialized( sessionId );
|
||||
}
|
||||
|
||||
void DebuggerClient::debuggeeRunning() {
|
||||
void DebuggerClient::debuggeeRunning( const SessionId& sessionId ) {
|
||||
for ( auto listener : mListeners )
|
||||
listener->debuggeeRunning();
|
||||
listener->debuggeeRunning( sessionId );
|
||||
}
|
||||
|
||||
void DebuggerClient::debuggeeTerminated() {
|
||||
void DebuggerClient::debuggeeTerminated( const SessionId& sessionId ) {
|
||||
for ( auto listener : mListeners )
|
||||
listener->debuggeeTerminated();
|
||||
listener->debuggeeTerminated( sessionId );
|
||||
}
|
||||
|
||||
void DebuggerClient::failed() {
|
||||
void DebuggerClient::failed( const SessionId& sessionId ) {
|
||||
for ( auto listener : mListeners )
|
||||
listener->failed();
|
||||
}
|
||||
|
||||
void DebuggerClient::setState( const State& state ) {
|
||||
if ( state != mState ) {
|
||||
mState = state;
|
||||
stateChanged( mState );
|
||||
|
||||
switch ( mState ) {
|
||||
case State::Initialized:
|
||||
initialized();
|
||||
checkRunning();
|
||||
break;
|
||||
case State::Running:
|
||||
debuggeeRunning();
|
||||
break;
|
||||
case State::Terminated:
|
||||
debuggeeTerminated();
|
||||
break;
|
||||
case State::Failed:
|
||||
failed();
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerClient::checkRunning() {
|
||||
if ( mLaunched && mConfigured && mState == State::Initialized ) {
|
||||
setState( State::Running );
|
||||
}
|
||||
listener->failed( sessionId );
|
||||
}
|
||||
|
||||
void DebuggerClient::addListener( Listener* listener ) {
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace ecode {
|
||||
|
||||
using namespace dap;
|
||||
|
||||
using SessionId = std::string;
|
||||
|
||||
class DebuggerClient {
|
||||
public:
|
||||
enum class State { None, Initializing, Initialized, Running, Terminated, Failed };
|
||||
@@ -15,43 +17,73 @@ class DebuggerClient {
|
||||
|
||||
class Listener {
|
||||
public:
|
||||
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;
|
||||
virtual void stateChanged( State, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void initialized( const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void launched( const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void configured( const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void failed( const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void debuggeeRunning( const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void debuggeeTerminated( const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void capabilitiesReceived( const Capabilities& capabilities ) = 0;
|
||||
virtual void debuggeeExited( int exitCode ) = 0;
|
||||
virtual void debuggeeStopped( const StoppedEvent& ) = 0;
|
||||
virtual void debuggeeContinued( const ContinuedEvent& ) = 0;
|
||||
virtual void outputProduced( const Output& ) = 0;
|
||||
virtual void debuggingProcess( const ProcessInfo& ) = 0;
|
||||
virtual void errorResponse( const std::string& command, const std::string& summary,
|
||||
const std::optional<Message>& message ) = 0;
|
||||
virtual void threadChanged( const ThreadEvent& ) = 0;
|
||||
virtual void moduleChanged( const ModuleEvent& ) = 0;
|
||||
virtual void threads( std::vector<DapThread>&& ) = 0;
|
||||
virtual void stackTrace( const int threadId, StackTraceInfo&& ) = 0;
|
||||
virtual void scopes( const int frameId, std::vector<Scope>&& ) = 0;
|
||||
virtual void variables( const int variablesReference, std::vector<Variable>&& ) = 0;
|
||||
virtual void modules( ModulesInfo&& ) = 0;
|
||||
virtual void serverDisconnected() = 0;
|
||||
virtual void sourceContent( const std::string& path, int reference = 0,
|
||||
const SourceContent& content = SourceContent() ) = 0;
|
||||
virtual void
|
||||
sourceBreakpoints( const std::string& path, int reference,
|
||||
const std::optional<std::vector<Breakpoint>>& breakpoints ) = 0;
|
||||
virtual void breakpointChanged( const BreakpointEvent& ) = 0;
|
||||
virtual void expressionEvaluated( const std::string& expression,
|
||||
const std::optional<EvaluateInfo>& ) = 0;
|
||||
virtual void gotoTargets( const Source& source, const int line,
|
||||
const std::vector<GotoTarget>& targets ) = 0;
|
||||
};
|
||||
|
||||
State state() const { return mState; }
|
||||
virtual void debuggeeExited( int exitCode, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void debuggeeStopped( const StoppedEvent&, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void debuggeeContinued( const ContinuedEvent&, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void outputProduced( const Output& ) = 0;
|
||||
|
||||
virtual void debuggingProcess( const ProcessInfo&, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void errorResponse( const std::string& command, const std::string& summary,
|
||||
const std::optional<Message>& message,
|
||||
const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void threadChanged( const ThreadEvent&, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void moduleChanged( const ModuleEvent&, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void threads( std::vector<DapThread>&&, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void stackTrace( const int threadId, StackTraceInfo&&,
|
||||
const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void scopes( const int frameId, std::vector<Scope>&&,
|
||||
const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void variables( const int variablesReference, std::vector<Variable>&&,
|
||||
const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void modules( ModulesInfo&&, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void serverDisconnected( const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void sourceContent( const std::string& path, int reference = 0,
|
||||
const SourceContent& content = SourceContent(),
|
||||
const SessionId& sessionId = "" ) = 0;
|
||||
|
||||
virtual void sourceBreakpoints( const std::string& path, int reference,
|
||||
const std::optional<std::vector<Breakpoint>>& breakpoints,
|
||||
const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void breakpointChanged( const BreakpointEvent&, const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void expressionEvaluated( const std::string& expression,
|
||||
const std::optional<EvaluateInfo>&,
|
||||
const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void gotoTargets( const Source& source, const int line,
|
||||
const std::vector<GotoTarget>& targets,
|
||||
const SessionId& sessionId ) = 0;
|
||||
};
|
||||
|
||||
virtual bool start() = 0;
|
||||
|
||||
@@ -113,7 +145,7 @@ class DebuggerClient {
|
||||
|
||||
virtual bool watch( const std::string& expression, std::optional<int> frameId ) = 0;
|
||||
|
||||
virtual bool configurationDone() = 0;
|
||||
virtual bool configurationDone( const SessionId& sessionId ) = 0;
|
||||
|
||||
virtual void setSilent( bool silent ) = 0;
|
||||
|
||||
@@ -123,22 +155,20 @@ class DebuggerClient {
|
||||
|
||||
virtual ~DebuggerClient() {}
|
||||
|
||||
protected:
|
||||
void setState( const State& state );
|
||||
virtual size_t sessionsActive() = 0;
|
||||
|
||||
protected:
|
||||
virtual void setState( const State& state, const SessionId& sessionId = "" ) = 0;
|
||||
|
||||
virtual void checkRunning( const SessionId& sessionId = "" ) = 0;
|
||||
|
||||
State mState{ State::None };
|
||||
bool mLaunched{ false };
|
||||
bool mConfigured{ false };
|
||||
bool mWaitingToAttach{ false };
|
||||
std::vector<Listener*> mListeners;
|
||||
|
||||
void checkRunning();
|
||||
|
||||
void stateChanged( State );
|
||||
void initialized();
|
||||
void debuggeeRunning();
|
||||
void debuggeeTerminated();
|
||||
void failed();
|
||||
void stateChanged( State, const SessionId& sessionId = "" );
|
||||
void initialized( const SessionId& sessionId = "" );
|
||||
void debuggeeRunning( const SessionId& sessionId = "" );
|
||||
void debuggeeTerminated( const SessionId& sessionId = "" );
|
||||
void failed( const SessionId& sessionId = "" );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -184,7 +184,7 @@ void DebuggerClientListener::initUI() {
|
||||
mPlugin->setUIDebuggingState( StatusDebuggerController::State::Running );
|
||||
}
|
||||
|
||||
void DebuggerClientListener::stateChanged( DebuggerClient::State state ) {
|
||||
void DebuggerClientListener::stateChanged( DebuggerClient::State state, const SessionId& ) {
|
||||
if ( state == DebuggerClient::State::Initializing ) {
|
||||
mPlugin->getManager()->getUISceneNode()->runOnMainThread( [this] { initUI(); } );
|
||||
}
|
||||
@@ -225,24 +225,26 @@ void DebuggerClientListener::setRemoteRoot( const std::string& newRemoteRoot ) {
|
||||
mRemoteRoot = newRemoteRoot;
|
||||
}
|
||||
|
||||
void DebuggerClientListener::initialized() {
|
||||
void DebuggerClientListener::initialized( const SessionId& ) {
|
||||
sendBreakpoints();
|
||||
}
|
||||
|
||||
void DebuggerClientListener::launched() {}
|
||||
void DebuggerClientListener::launched( const SessionId& ) {}
|
||||
|
||||
void DebuggerClientListener::configured() {}
|
||||
void DebuggerClientListener::configured( const SessionId& ) {}
|
||||
|
||||
void DebuggerClientListener::failed() {
|
||||
void DebuggerClientListener::failed( const SessionId& ) {
|
||||
mPlugin->exitDebugger();
|
||||
resetState();
|
||||
}
|
||||
|
||||
void DebuggerClientListener::debuggeeRunning() {}
|
||||
void DebuggerClientListener::debuggeeRunning( const SessionId& ) {}
|
||||
|
||||
void DebuggerClientListener::debuggeeTerminated() {
|
||||
mPlugin->exitDebugger();
|
||||
resetState();
|
||||
void DebuggerClientListener::debuggeeTerminated( const SessionId& ) {
|
||||
if ( mClient->sessionsActive() == 0 ) {
|
||||
mPlugin->exitDebugger();
|
||||
resetState();
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerClientListener::capabilitiesReceived( const Capabilities& /*capabilities*/ ) {}
|
||||
@@ -258,12 +260,12 @@ void DebuggerClientListener::resetState() {
|
||||
mVariablesHolder->clear();
|
||||
}
|
||||
|
||||
void DebuggerClientListener::debuggeeExited( int /*exitCode*/ ) {
|
||||
void DebuggerClientListener::debuggeeExited( int /*exitCode*/, const SessionId& ) {
|
||||
mPlugin->exitDebugger();
|
||||
resetState();
|
||||
}
|
||||
|
||||
void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) {
|
||||
void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event, const SessionId& ) {
|
||||
Log::debug( "DebuggerClientListener::debuggeeStopped: reason %s", event.reason );
|
||||
|
||||
for ( auto& [editor, _] : mPlugin->mEditors ) {
|
||||
@@ -309,7 +311,7 @@ void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) {
|
||||
sdc->getWidget()->runOnMainThread( [sdc] { sdc->show(); } );
|
||||
}
|
||||
|
||||
void DebuggerClientListener::debuggeeContinued( const ContinuedEvent& ) {
|
||||
void DebuggerClientListener::debuggeeContinued( const ContinuedEvent&, const SessionId& ) {
|
||||
resetState();
|
||||
|
||||
UISceneNode* sceneNode = mPlugin->getUISceneNode();
|
||||
@@ -339,27 +341,28 @@ void DebuggerClientListener::outputProduced( const Output& output ) {
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerClientListener::debuggingProcess( const ProcessInfo& info ) {
|
||||
void DebuggerClientListener::debuggingProcess( const ProcessInfo& info, const SessionId& ) {
|
||||
mProcessInfo = info;
|
||||
}
|
||||
|
||||
void DebuggerClientListener::errorResponse( const std::string& command, const std::string& summary,
|
||||
const std::optional<Message>& /*message*/ ) {
|
||||
const std::optional<Message>& /*message*/,
|
||||
const SessionId& sessionId ) {
|
||||
if ( command == "evaluate" )
|
||||
return;
|
||||
|
||||
if ( command == "launch" )
|
||||
failed();
|
||||
failed( sessionId );
|
||||
|
||||
mPlugin->getPluginContext()->getNotificationCenter()->addNotification( summary, Seconds( 5 ),
|
||||
true );
|
||||
}
|
||||
|
||||
void DebuggerClientListener::threadChanged( const ThreadEvent& ) {}
|
||||
void DebuggerClientListener::threadChanged( const ThreadEvent&, const std::string& ) {}
|
||||
|
||||
void DebuggerClientListener::moduleChanged( const ModuleEvent& ) {}
|
||||
void DebuggerClientListener::moduleChanged( const ModuleEvent&, const std::string& ) {}
|
||||
|
||||
void DebuggerClientListener::threads( std::vector<DapThread>&& threads ) {
|
||||
void DebuggerClientListener::threads( std::vector<DapThread>&& threads, const SessionId& ) {
|
||||
std::sort( threads.begin(), threads.end(),
|
||||
[]( const DapThread& a, const DapThread& b ) { return a.id < b.id; } );
|
||||
|
||||
@@ -379,8 +382,9 @@ void DebuggerClientListener::changeScope( const StackFrame& f ) {
|
||||
TextRange range{ { f.line - 1, f.column - 1 }, { f.line - 1, f.column - 1 } };
|
||||
std::string path( f.source->path );
|
||||
|
||||
mPlugin->getUISceneNode()->runOnMainThread(
|
||||
[this, path, range] { mPlugin->getPluginContext()->focusOrLoadFile( path, range ); } );
|
||||
mPlugin->getUISceneNode()->runOnMainThread( [this, path, range] {
|
||||
mPlugin->getPluginContext()->focusOrLoadFile( path, range );
|
||||
} );
|
||||
|
||||
mCurrentScopePos = { f.source->path, f.line };
|
||||
|
||||
@@ -399,7 +403,8 @@ void DebuggerClientListener::changeThread( int id ) {
|
||||
sdc->getUIThreads()->setSelection( mThreadsModel->fromThreadId( id ) );
|
||||
}
|
||||
|
||||
void DebuggerClientListener::stackTrace( const int threadId, StackTraceInfo&& stack ) {
|
||||
void DebuggerClientListener::stackTrace( const int threadId, StackTraceInfo&& stack,
|
||||
const SessionId& ) {
|
||||
changeThread( threadId );
|
||||
|
||||
for ( const auto& f : stack.stackFrames ) {
|
||||
@@ -436,7 +441,8 @@ void DebuggerClientListener::stackTrace( const int threadId, StackTraceInfo&& st
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerClientListener::scopes( const int /*frameId*/, std::vector<Scope>&& scopes ) {
|
||||
void DebuggerClientListener::scopes( const int /*frameId*/, std::vector<Scope>&& scopes,
|
||||
const SessionId& ) {
|
||||
if ( scopes.empty() )
|
||||
return;
|
||||
|
||||
@@ -480,8 +486,8 @@ void DebuggerClientListener::scopes( const int /*frameId*/, std::vector<Scope>&&
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerClientListener::variables( const int variablesReference,
|
||||
std::vector<Variable>&& vars ) {
|
||||
void DebuggerClientListener::variables( const int variablesReference, std::vector<Variable>&& vars,
|
||||
const SessionId& ) {
|
||||
mVariablesHolder->addVariables( variablesReference, std::move( vars ) );
|
||||
|
||||
auto scopeIt = mScopeRef.find( variablesReference );
|
||||
@@ -493,24 +499,26 @@ void DebuggerClientListener::variables( const int variablesReference,
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerClientListener::modules( ModulesInfo&& ) {}
|
||||
void DebuggerClientListener::modules( ModulesInfo&&, const SessionId& ) {}
|
||||
|
||||
void DebuggerClientListener::serverDisconnected() {}
|
||||
void DebuggerClientListener::serverDisconnected( const SessionId& ) {}
|
||||
|
||||
void DebuggerClientListener::sourceContent( const std::string& /*path*/, int /*reference*/,
|
||||
const SourceContent& /*content*/ ) {}
|
||||
const SourceContent& /*content*/, const SessionId& ) {}
|
||||
|
||||
void DebuggerClientListener::sourceBreakpoints(
|
||||
const std::string& /*path*/, int /*reference*/,
|
||||
const std::optional<std::vector<Breakpoint>>& /*breakpoints*/ ) {}
|
||||
const std::optional<std::vector<Breakpoint>>& /*breakpoints*/, const SessionId& ) {}
|
||||
|
||||
void DebuggerClientListener::breakpointChanged( const BreakpointEvent& ) {}
|
||||
void DebuggerClientListener::breakpointChanged( const BreakpointEvent&, const SessionId& ) {}
|
||||
|
||||
void DebuggerClientListener::expressionEvaluated( const std::string& /*expression*/,
|
||||
const std::optional<EvaluateInfo>& ) {}
|
||||
const std::optional<EvaluateInfo>&,
|
||||
const SessionId& ) {}
|
||||
|
||||
void DebuggerClientListener::gotoTargets( const Source& /*source*/, const int /*line*/,
|
||||
const std::vector<GotoTarget>& /*targets*/ ) {}
|
||||
const std::vector<GotoTarget>& /*targets*/,
|
||||
const SessionId& ) {}
|
||||
|
||||
bool DebuggerClientListener::isRemote() const {
|
||||
return mIsRemote;
|
||||
|
||||
@@ -20,38 +20,66 @@ class DebuggerClientListener : public DebuggerClient::Listener {
|
||||
|
||||
virtual ~DebuggerClientListener();
|
||||
|
||||
void stateChanged( DebuggerClient::State );
|
||||
void initialized();
|
||||
void launched();
|
||||
void configured();
|
||||
void failed();
|
||||
void debuggeeRunning();
|
||||
void debuggeeTerminated();
|
||||
void stateChanged( DebuggerClient::State, const SessionId& sessionId );
|
||||
|
||||
void initialized( const SessionId& sessionId );
|
||||
|
||||
void launched( const SessionId& sessionId );
|
||||
|
||||
void configured( const SessionId& sessionId );
|
||||
|
||||
void failed( const SessionId& sessionId );
|
||||
|
||||
void debuggeeRunning( const SessionId& sessionId );
|
||||
|
||||
void debuggeeTerminated( const SessionId& sessionId );
|
||||
|
||||
void capabilitiesReceived( const Capabilities& capabilities );
|
||||
void debuggeeExited( int exitCode );
|
||||
void debuggeeStopped( const StoppedEvent& );
|
||||
void debuggeeContinued( const ContinuedEvent& );
|
||||
|
||||
void debuggeeExited( int exitCode, const SessionId& sessionId );
|
||||
|
||||
void debuggeeStopped( const StoppedEvent&, const SessionId& sessionId );
|
||||
|
||||
void debuggeeContinued( const ContinuedEvent&, const SessionId& sessionId );
|
||||
|
||||
void outputProduced( const Output& );
|
||||
void debuggingProcess( const ProcessInfo& );
|
||||
void debuggingProcess( const ProcessInfo&, const SessionId& sessionId );
|
||||
|
||||
void errorResponse( const std::string& command, const std::string& summary,
|
||||
const std::optional<Message>& message );
|
||||
void threadChanged( const ThreadEvent& );
|
||||
void moduleChanged( const ModuleEvent& );
|
||||
void threads( std::vector<DapThread>&& );
|
||||
void stackTrace( const int threadId, StackTraceInfo&& );
|
||||
void scopes( const int frameId, std::vector<Scope>&& );
|
||||
void variables( const int variablesReference, std::vector<Variable>&& );
|
||||
void modules( ModulesInfo&& );
|
||||
void serverDisconnected();
|
||||
const std::optional<Message>& message, const SessionId& sessionId );
|
||||
|
||||
void threadChanged( const ThreadEvent&, const SessionId& sessionId );
|
||||
|
||||
void moduleChanged( const ModuleEvent&, const SessionId& sessionId );
|
||||
|
||||
void threads( std::vector<DapThread>&&, const SessionId& sessionId );
|
||||
|
||||
void stackTrace( const int threadId, StackTraceInfo&&, const SessionId& sessionId );
|
||||
|
||||
void scopes( const int frameId, std::vector<Scope>&&, const SessionId& sessionId );
|
||||
|
||||
void variables( const int variablesReference, std::vector<Variable>&&,
|
||||
const SessionId& sessionId );
|
||||
|
||||
void modules( ModulesInfo&&, const SessionId& sessionId );
|
||||
|
||||
void serverDisconnected( const SessionId& sessionId );
|
||||
|
||||
void sourceContent( const std::string& path, int reference,
|
||||
const SourceContent& content = SourceContent() );
|
||||
const SourceContent& content = SourceContent(),
|
||||
const SessionId& sessionId = "" );
|
||||
|
||||
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 );
|
||||
const std::optional<std::vector<Breakpoint>>& breakpoints,
|
||||
const SessionId& sessionId );
|
||||
|
||||
void breakpointChanged( const BreakpointEvent&, const SessionId& sessionId );
|
||||
|
||||
void expressionEvaluated( const std::string& expression, const std::optional<EvaluateInfo>&,
|
||||
const SessionId& sessionId );
|
||||
|
||||
void gotoTargets( const Source& source, const int line, const std::vector<GotoTarget>& targets,
|
||||
const SessionId& sessionId );
|
||||
|
||||
bool isRemote() const;
|
||||
|
||||
|
||||
@@ -73,6 +73,9 @@ static constexpr auto KEY_DEFAULT_BUILD_TASK = "${defaultBuildTask}";
|
||||
static constexpr auto KEY_PATH_SEPARATOR = "${pathSeparator}";
|
||||
static constexpr auto KEY_PATH_SEPARATOR_ABBR = "${/}";
|
||||
|
||||
static constexpr auto KEY_UUID = "${uuid}";
|
||||
static constexpr auto KEY_TIMESTAMP = "${timestamp}";
|
||||
|
||||
static constexpr auto KEY_DEBUG_SERVER = "debugServer";
|
||||
|
||||
static void replaceExecutableArgs( std::string& arg ) {
|
||||
@@ -1154,6 +1157,10 @@ void DebuggerPlugin::replaceInVal( std::string& val,
|
||||
String::replaceAll( val, KEY_EXEC_PATH, Sys::getProcessFilePath() );
|
||||
String::replaceAll( val, KEY_PATH_SEPARATOR, FileSystem::getOSSlash() );
|
||||
String::replaceAll( val, KEY_PATH_SEPARATOR_ABBR, FileSystem::getOSSlash() );
|
||||
String::replaceAll( val, KEY_UUID, UUID().toString() );
|
||||
String::replaceAll( val, KEY_TIMESTAMP,
|
||||
std::to_string( std::chrono::system_clock::to_time_t(
|
||||
std::chrono::system_clock::now() ) ) );
|
||||
|
||||
auto* editor = getPluginContext()->getSplitter()->getCurEditor();
|
||||
if ( getPluginContext()->getSplitter()->getCurEditor() ) {
|
||||
@@ -1759,7 +1766,7 @@ void DebuggerPlugin::runConfig( const std::string& debugger, const std::string&
|
||||
mDapConfigs.begin(), mDapConfigs.end(),
|
||||
[&configuration]( const DapConfig& conf ) { return conf.name == configuration; } );
|
||||
|
||||
if ( configIt == debuggerIt->configurations.end() )
|
||||
if ( configIt == mDapConfigs.end() )
|
||||
return;
|
||||
|
||||
usingExternalConfig = true;
|
||||
|
||||
@@ -119,7 +119,8 @@ class PluginContextProvider {
|
||||
|
||||
virtual std::string getCurrentWorkingDir() const = 0;
|
||||
|
||||
virtual void focusOrLoadFile( const std::string& path, const TextRange& range = {} ) = 0;
|
||||
virtual void focusOrLoadFile( const std::string& path, const TextRange& range = {},
|
||||
bool searchInSameContext = false ) = 0;
|
||||
|
||||
virtual void runCommand( const std::string& command ) = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user