Repository: godotengine/godot (language: cpp)

Issue:
Documentation tooltips appear over debugger tooltips
### Tested versions

4.4 dev7

### System information

W10

### Issue description

https://github.com/user-attachments/assets/12ac6f85-8a1f-43c9-9f5a-16dffcbab8d9


### Steps to reproduce

1. Run a project
2. Do a debugger break (breakpoint, pause etc.)
3. Hover over a variable to display its value
4. Documentation tooltip will appear over debugger's tooltip

### Minimal reproduction project (MRP)

N/A
Documentation tooltips appear over debugger tooltips
### Tested versions

4.4 dev7

### System information

W10

### Issue description

https://github.com/user-attachments/assets/12ac6f85-8a1f-43c9-9f5a-16dffcbab8d9


### Steps to reproduce

1. Run a project
2. Do a debugger break (breakpoint, pause etc.)
3. Hover over a variable to display its value
4. Documentation tooltip will appear over debugger's tooltip

### Minimal reproduction project (MRP)

N/A


Discussion / hints:
Amusingly, by [accepting @Calinou suggestion to have them display above](https://github.com/godotengine/godot/pull/91060#pullrequestreview-2503361244), this would not be an issue. @dalexeev 
Same behaviour on Mac, tooltip is hiding the property debugging value.

![Image](https://github.com/user-attachments/assets/9df8e181-ea69-4d96-a2e1-ce35fd7e48b1)

Amusingly, by [accepting @Calinou suggestion to have them display above](https://github.com/godotengine/godot/pull/91060#pullrequestreview-2503361244), this would not be an issue. @dalexeev 
Same behaviour on Mac, tooltip is hiding the property debugging value.

![Image](https://github.com/user-attachments/assets/9df8e181-ea69-4d96-a2e1-ce35fd7e48b1)


Fix patch:
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 6248592b5101..c11b107ee380 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -497,19 +497,6 @@ ScriptEditor *ScriptEditor::script_editor = nullptr;
 
 /*** SCRIPT EDITOR ******/
 
-String ScriptEditor::_get_debug_tooltip(const String &p_text, Node *_se) {
-	String val = EditorDebuggerNode::get_singleton()->get_var_value(p_text);
-	const int display_limit = 300;
-	if (!val.is_empty()) {
-		if (val.size() > display_limit) {
-			val = val.left(display_limit) + " [...] truncated!";
-		}
-		return p_text + ": " + val;
-	} else {
-		return String();
-	}
-}
-
 void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) {
 	if (external_editor_active) {
 		return;
@@ -2633,7 +2620,6 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
 	// If we delete a script within the filesystem, the original resource path
 	// is lost, so keep it as metadata to figure out the exact tab to delete.
 	se->set_meta("_edit_res_path", p_resource->get_path());
-	se->set_tooltip_request_func(callable_mp(this, &ScriptEditor::_get_debug_tooltip));
 	if (se->get_edit_menu()) {
 		se->get_edit_menu()->hide();
 		menu_hb->add_child(se->get_edit_menu());
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 2f5560bdab4f..146e064d08e7 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -378,8 +378,6 @@ class ScriptEditor : public PanelContainer {
 
 	bool restoring_layout;
 
-	String _get_debug_tooltip(const String &p_text, Node *_se);
-
 	void _resave_scripts(const String &p_str);
 
 	bool _test_script_times_on_disk(Ref<Resource> p_for_script = Ref<Resource>());
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 1af0fd692d3f..aa5752820c29 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1107,99 +1107,112 @@ void ScriptTextEditor::_show_symbol_tooltip(const String &p_symbol, int p_row, i
 	}
 
 	ScriptLanguage::LookupResult result;
+	String doc_symbol;
 	const String code_text = code_editor->get_text_editor()->get_text_with_cursor_char(p_row, p_column);
 	const Error lc_error = script->get_language()->lookup_code(code_text, p_symbol, script->get_path(), base, result);
-	if (lc_error != OK) {
-		return;
-	}
-
-	String doc_symbol;
-	switch (result.type) {
-		case ScriptLanguage::LOOKUP_RESULT_CLASS: {
-			doc_symbol = "class|" + result.class_name + "|";
-		} break;
-		case ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT: {
-			StringName cname = result.class_name;
-			while (ClassDB::class_exists(cname)) {
-				if (ClassDB::has_integer_constant(cname, result.class_member, true)) {
-					result.class_name = cname;
-					break;
+	if (lc_error == OK) {
+		switch (result.type) {
+			case ScriptLanguage::LOOKUP_RESULT_CLASS: {
+				doc_symbol = "class|" + result.class_name + "|";
+			} break;
+			case ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT: {
+				StringName cname = result.class_name;
+				while (ClassDB::class_exists(cname)) {
+					if (ClassDB::has_integer_constant(cname, result.class_member, true)) {
+						result.class_name = cname;
+						break;
+					}
+					cname = ClassDB::get_parent_class(cname);
 				}
-				cname = ClassDB::get_parent_class(cname);
-			}
-			doc_symbol = "constant|" + result.class_name + "|" + result.class_member;
-		} break;
-		case ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY: {
-			StringName cname = result.class_name;
-			while (ClassDB::class_exists(cname)) {
-				if (ClassDB::has_property(cname, result.class_member, true)) {
-					result.class_name = cname;
-					break;
+				doc_symbol = "constant|" + result.class_name + "|" + result.class_member;
+			} break;
+			case ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY: {
+				StringName cname = result.class_name;
+				while (ClassDB::class_exists(cname)) {
+					if (ClassDB::has_property(cname, result.class_member, true)) {
+						result.class_name = cname;
+						break;
+					}
+					cname = ClassDB::get_parent_class(cname);
 				}
-				cname = ClassDB::get_parent_class(cname);
-			}
-			doc_symbol = "property|" + result.class_name + "|" + result.class_member;
-		} break;
-		case ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD: {
-			StringName cname = result.class_name;
-			while (ClassDB::class_exists(cname)) {
-				if (ClassDB::has_method(cname, result.class_member, true)) {
-					result.class_name = cname;
-					break;
+				doc_symbol = "property|" + result.class_name + "|" + result.class_member;
+			} break;
+			case ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD: {
+				StringName cname = result.class_name;
+				while (ClassDB::class_exists(cname)) {
+					if (ClassDB::has_method(cname, result.class_member, true)) {
+						result.class_name = cname;
+						break;
+					}
+					cname = ClassDB::get_parent_class(cname);
 				}
-				cname = ClassDB::get_parent_class(cname);
-			}
-			doc_symbol = "method|" + result.class_name + "|" + result.class_member;
-		} break;
-		case ScriptLanguage::LOOKUP_RESULT_CLASS_SIGNAL: {
-			StringName cname = result.class_name;
-			while (ClassDB::class_exists(cname)) {
-				if (ClassDB::has_signal(cname, result.class_member, true)) {
-					result.class_name = cname;
-					break;
+				doc_symbol = "method|" + result.class_name + "|" + result.class_member;
+			} break;
+			case ScriptLanguage::LOOKUP_RESULT_CLASS_SIGNAL: {
+				StringName cname = result.class_name;
+				while (ClassDB::class_exists(cname)) {
+					if (ClassDB::has_signal(cname, result.class_member, true)) {
+						result.class_name = cname;
+						break;
+					}
+					cname = ClassDB::get_parent_class(cname);
 				}
-				cname = ClassDB::get_parent_class(cname);
-			}
-			doc_symbol = "signal|" + result.class_name + "|" + result.class_member;
-		} break;
-		case ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM: {
-			StringName cname = result.class_name;
-			while (ClassDB::class_exists(cname)) {
-				if (ClassDB::has_enum(cname, result.class_member, true)) {
-					result.class_name = cname;
-					break;
+				doc_symbol = "signal|" + result.class_name + "|" + result.class_member;
+			} break;
+			case ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM: {
+				StringName cname = result.class_name;
+				while (ClassDB::class_exists(cname)) {
+					if (ClassDB::has_enum(cname, result.class_member, true)) {
+						result.class_name = cname;
+						break;
+					}
+					cname = ClassDB::get_parent_class(cname);
 				}
-				cname = ClassDB::get_parent_class(cname);
-			}
-			doc_symbol = "enum|" + result.class_name + "|" + result.class_member;
-		} break;
-		case ScriptLanguage::LOOKUP_RESULT_CLASS_ANNOTATION: {
-			doc_symbol = "annotation|" + result.class_name + "|" + result.class_member;
-		} break;
-		case ScriptLanguage::LOOKUP_RESULT_LOCAL_CONSTANT:
-		case ScriptLanguage::LOOKUP_RESULT_LOCAL_VARIABLE: {
-			const String item_type = (result.type == ScriptLanguage::LOOKUP_RESULT_LOCAL_CONSTANT) ? "local_constant" : "local_variable";
-			Dictionary item_data;
-			item_data["description"] = result.description;
-			item_data["is_deprecated"] = result.is_deprecated;
-			item_data["deprecated_message"] = result.deprecated_message;
-			item_data["is_experimental"] = result.is_experimental;
-			item_data["experimental_message"] = result.experimental_message;
-			item_data["doc_type"] = result.doc_type;
-			item_data["enumeration"] = result.enumeration;
-			item_data["is_bitfield"] = result.is_bitfield;
-			item_data["value"] = result.value;
-			doc_symbol = item_type + "||" + p_symbol + "|" + JSON::stringify(item_data);
-		} break;
-		case ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION:
-		case ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE: // Deprecated.
-		case ScriptLanguage::LOOKUP_RESULT_MAX: {
-			// Nothing to do.
-		} break;
+				doc_symbol = "enum|" + result.class_name + "|" + result.class_member;
+			} break;
+			case ScriptLanguage::LOOKUP_RESULT_CLASS_ANNOTATION: {
+				doc_symbol = "annotation|" + result.class_name + "|" + result.class_member;
+			} break;
+			case ScriptLanguage::LOOKUP_RESULT_LOCAL_CONSTANT:
+			case ScriptLanguage::LOOKUP_RESULT_LOCAL_VARIABLE: {
+				const String item_type = (result.type == ScriptLanguage::LOOKUP_RESULT_LOCAL_CONSTANT) ? "local_constant" : "local_variable";
+				Dictionary item_data;
+				item_data["description"] = result.description;
+				item_data["is_deprecated"] = result.is_deprecated;
+				item_data["deprecated_message"] = result.deprecated_message;
+				item_data["is_experimental"] = result.is_experimental;
+				item_data["experimental_message"] = result.experimental_message;
+				item_data["doc_type"] = result.doc_type;
+				item_data["enumeration"] = result.enumeration;
+				item_data["is_bitfield"] = result.is_bitfield;
+				item_data["value"] = result.value;
+				doc_symbol = item_type + "||" + p_symbol + "|" + JSON::stringify(item_data);
+			} break;
+			case ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION:
+			case ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE: // Deprecated.
+			case ScriptLanguage::LOOKUP_RESULT_MAX: {
+				// Nothing to do.
+			} break;
+		}
+	}
+
+	String debug_value = EditorDebuggerNode::get_singleton()->get_var_value(p_symbol);
+	if (!debug_value.is_empty()) {
+		constexpr int DISPLAY_LIMIT = 1024;
+		if (debug_value.size() > DISPLAY_LIMIT) {
+			debug_value = debug_value.left(DISPLAY_LIMIT) + "... " + TTR("(truncated)");
+		}
+		debug_value = debug_value.replace("[", "[lb]");
+
+		if (doc_symbol.is_empty()) {
+			debug_value = p_symbol + ": " + debug_value;
+		} else {
+			debug_value = TTR("Current value: ") + debug_value;
+		}
 	}
 
-	if (!doc_symbol.is_empty()) {
-		EditorHelpBitTooltip::show_tooltip(code_editor->get_text_editor(), doc_symbol, String(), true);
+	if (!doc_symbol.is_empty() || !debug_value.is_empty()) {
+		EditorHelpBitTooltip::show_tooltip(code_editor->get_text_editor(), doc_symbol, debug_value, true);
 	}
 }
 


Test patch: