From 6abcb2a8dbbfdcb3b0372b2d9e41f3fe899b195b Mon Sep 17 00:00:00 2001 From: Filipe Abreu Date: Thu, 28 May 2026 22:42:53 +0100 Subject: [PATCH] Implement NodePath Navigation in the Godot Script Editor (Ctrl+Click) This feature adds IDE-style "Go to Definition" support for static NodePaths inside the Script Editor. When the user Ctrl+Clicks a NodePath such as $Node/LineEdit or get_node("UI/HUD/HealthBar"), the editor resolves the path relative to the script owner and automatically selects the matching node in the Scene Tree. If multiple valid matches exist because the same script is attached to multiple scene instances, a popup is shown so the user can choose the intended target. Dynamic NodePaths such as get_node(path_var) are excluded from the initial scope to keep the implementation simpler and more reliable. Example: NodeA (Script X.gd) --- Node/LineEdit NodeB (Script X.gd) --- Node/LineEdit Ctrl+Clicking $Node/LineEdit would display a popup listing both possible destinations. Co-authored-by: Joana Vaz --- editor/script/script_text_editor.cpp | 154 ++++++++++++++++++++++++- editor/script/script_text_editor.h | 10 ++ scene/gui/code_edit.cpp | 75 ++++++++++++ scene/gui/code_edit.h | 1 + tests/scene/test_code_edit.cpp | 165 +++++++++++++++++++++++++++ 5 files changed, 402 insertions(+), 3 deletions(-) diff --git a/editor/script/script_text_editor.cpp b/editor/script/script_text_editor.cpp index a609616bd37f..2c371b95589c 100644 --- a/editor/script/script_text_editor.cpp +++ b/editor/script/script_text_editor.cpp @@ -47,6 +47,7 @@ #include "editor/editor_string_names.h" #include "editor/gui/editor_toaster.h" #include "editor/inspector/editor_context_menu_plugin.h" +#include "editor/docks/scene_tree_dock.h" #include "editor/inspector/editor_inspector.h" #include "editor/inspector/multi_node_edit.h" #include "editor/script/syntax_highlighters.h" @@ -55,6 +56,7 @@ #include "editor/themes/editor_scale.h" #include "scene/gui/grid_container.h" #include "scene/gui/menu_button.h" +#include "scene/gui/item_list.h" #include "scene/gui/rich_text_label.h" #include "scene/gui/split_container.h" #include "scene/main/scene_tree.h" @@ -866,7 +868,7 @@ void ScriptTextEditor::_validate_script() { if (errors.size() > 0) { code_editor->set_error_pos(errors.front()->get().line - 1, errors.front()->get().column - 1); const String message = errors.front()->get().message.replace("[", "[lb]"); - const Point2i display_pos = code_editor->get_pos_for_display(code_editor->get_error_pos()); + const Point2i display_pos = code_editor->get_error_pos() + Point2i(1, 1); const String error_text = vformat(TTR("Error at ([hint=Line %d, column %d]%d, %d[/hint]):"), display_pos.x, display_pos.y, display_pos.x, display_pos.y) + " " + message; code_editor->set_error(error_text); } @@ -1188,6 +1190,12 @@ void ScriptTextEditor::_on_caret_moved() { } void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_column) { + CodeEdit *text_edit = code_editor->get_text_editor(); + String nodepath = text_edit->get_nodepath_at_pos(p_row, p_column); + if (!nodepath.is_empty() && _navigate_nodepath(p_row, p_column)) { + return; + } + Ref