diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp index 8e2f037a1c3..1dbb2c70846 100644 --- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp +++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp @@ -30,6 +30,8 @@ #include "debug_adapter_parser.h" +#include "core/variant/variant.h" +#include "editor/debugger/debug_adapter/debug_adapter_types.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/debugger/script_editor_debugger.h" #include "editor/export/editor_export_platform.h" @@ -487,16 +489,27 @@ Dictionary DebugAdapterParser::req_stepIn(const Dictionary &p_params) const { } Dictionary DebugAdapterParser::req_evaluate(const Dictionary &p_params) const { - Dictionary response = prepare_success_response(p_params), body; - response["body"] = body; - Dictionary args = p_params["arguments"]; + String expression = args["expression"]; + int frame_id = args.has("frameId") ? static_cast(args["frameId"]) : DebugAdapterProtocol::get_singleton()->_current_frame; - String value = EditorDebuggerNode::get_singleton()->get_var_value(args["expression"]); - body["result"] = value; - body["variablesReference"] = 0; + if (HashMap::Iterator E = DebugAdapterProtocol::get_singleton()->eval_list.find(expression); E) { + Dictionary response = prepare_success_response(p_params); + Dictionary body; + response["body"] = body; - return response; + DAP::Variable var = E->value; + + body["result"] = var.value; + body["variablesReference"] = var.variablesReference; + + // Since an evaluation can alter the state of the debuggee, they are volatile, and should only be used once + DebugAdapterProtocol::get_singleton()->eval_list.erase(E->key); + return response; + } else { + DebugAdapterProtocol::get_singleton()->request_remote_evaluate(expression, frame_id); + } + return Dictionary(); } Dictionary DebugAdapterParser::req_godot_put_msg(const Dictionary &p_params) const { diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp index a130464fe07..066cf633014 100644 --- a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp +++ b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp @@ -799,6 +799,22 @@ void DebugAdapterProtocol::parse_object(SceneDebuggerObject &p_obj) { variable_list.insert(object_list[object_id], properties); } +void DebugAdapterProtocol::parse_evaluation(DebuggerMarshalls::ScriptStackVariable &p_var) { + // If the eval is not on the pending list, we weren't expecting it. Ignore it. + String eval = p_var.name; + if (!eval_pending_list.erase(eval)) { + return; + } + + DAP::Variable variable; + variable.name = p_var.name; + variable.value = p_var.value; + variable.type = Variant::get_type_name(p_var.value.get_type()); + variable.variablesReference = parse_variant(p_var.value); + + eval_list.insert(variable.name, variable); +} + const Variant DebugAdapterProtocol::parse_object_variable(const SceneDebuggerObject::SceneDebuggerProperty &p_property) { const PropertyInfo &info = p_property.first; const Variant &value = p_property.second; @@ -833,6 +849,18 @@ bool DebugAdapterProtocol::request_remote_object(const ObjectID &p_object_id) { return true; } +bool DebugAdapterProtocol::request_remote_evaluate(const String &p_eval, int p_stack_frame) { + // If the eval is already on the pending list, we don't need to request it again + if (eval_pending_list.has(p_eval)) { + return false; + } + + EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_evaluate(p_eval, p_stack_frame); + eval_pending_list.insert(p_eval); + + return true; +} + bool DebugAdapterProtocol::process_message(const String &p_text) { JSON json; ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!"); @@ -1148,6 +1176,12 @@ void DebugAdapterProtocol::on_debug_data(const String &p_msg, const Array &p_dat remote_obj.deserialize(p_data); parse_object(remote_obj); + } else if (p_msg == "evaluation_return") { + // An evaluation was requested from the debuggee; parse it. + DebuggerMarshalls::ScriptStackVariable remote_evaluation; + remote_evaluation.deserialize(p_data); + + parse_evaluation(remote_evaluation); } notify_custom_data(p_msg, p_data); diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.h b/editor/debugger/debug_adapter/debug_adapter_protocol.h index 29d7457ee76..81e6205feef 100644 --- a/editor/debugger/debug_adapter/debug_adapter_protocol.h +++ b/editor/debugger/debug_adapter/debug_adapter_protocol.h @@ -31,9 +31,11 @@ #ifndef DEBUG_ADAPTER_PROTOCOL_H #define DEBUG_ADAPTER_PROTOCOL_H +#include "core/debugger/debugger_marshalls.h" #include "core/io/stream_peer_tcp.h" #include "core/io/tcp_server.h" +#include "core/object/object_id.h" #include "debug_adapter_parser.h" #include "debug_adapter_types.h" #include "scene/debugger/scene_debugger.h" @@ -103,9 +105,11 @@ private: int parse_variant(const Variant &p_var); void parse_object(SceneDebuggerObject &p_obj); const Variant parse_object_variable(const SceneDebuggerObject::SceneDebuggerProperty &p_property); + void parse_evaluation(DebuggerMarshalls::ScriptStackVariable &p_var); ObjectID search_object_id(DAPVarID p_var_id); bool request_remote_object(const ObjectID &p_object_id); + bool request_remote_evaluate(const String &p_eval, int p_stack_frame); bool _initialized = false; bool _processing_breakpoint = false; @@ -129,6 +133,9 @@ private: HashMap object_list; HashSet object_pending_set; + HashMap eval_list; + HashSet eval_pending_list; + public: friend class DebugAdapterServer; diff --git a/editor/debugger/editor_expression_evaluator.cpp b/editor/debugger/editor_expression_evaluator.cpp index e8b1e33d205..25e9c9eac37 100644 --- a/editor/debugger/editor_expression_evaluator.cpp +++ b/editor/debugger/editor_expression_evaluator.cpp @@ -64,10 +64,7 @@ void EditorExpressionEvaluator::_evaluate() { return; } - Array expr_data; - expr_data.push_back(expression); - expr_data.push_back(editor_debugger->get_stack_script_frame()); - editor_debugger->send_message("evaluate", expr_data); + editor_debugger->request_remote_evaluate(expression, editor_debugger->get_stack_script_frame()); expression_input->clear(); } diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 642244ebeb1..cbe7910518c 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -253,6 +253,13 @@ const SceneDebuggerTree *ScriptEditorDebugger::get_remote_tree() { return scene_tree; } +void ScriptEditorDebugger::request_remote_evaluate(const String &p_expression, int p_stack_frame) { + Array msg; + msg.push_back(p_expression); + msg.push_back(p_stack_frame); + _put_msg("evaluate", msg); +} + void ScriptEditorDebugger::update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value) { Array msg; msg.push_back(p_obj_id); diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h index 26106849f90..1908b1e5a7f 100644 --- a/editor/debugger/script_editor_debugger.h +++ b/editor/debugger/script_editor_debugger.h @@ -254,6 +254,8 @@ public: void request_remote_tree(); const SceneDebuggerTree *get_remote_tree(); + void request_remote_evaluate(const String &p_expression, int p_stack_frame); + void start(Ref p_peer); void stop();