Add DAP multi-session support and add Node.js debugging support.

This commit is contained in:
Martín Lucas Golini
2025-06-22 01:48:17 -03:00
parent 03df17b96b
commit 5cc94842e1
17 changed files with 870 additions and 516 deletions
+34 -2
View File
@@ -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 -2
View File
@@ -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>
+2 -1
View File
@@ -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 ) );
}
+3 -2
View File
@@ -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() )
+2 -1
View File
@@ -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; }
+4
View File
@@ -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;