mirror of
https://github.com/godotengine/godot.git
synced 2025-10-25 18:54:43 +00:00
Code Editor: Add documentation tooltips
This commit is contained in:
parent
863a24ac86
commit
80d11500b5
30 changed files with 1398 additions and 586 deletions
|
|
@ -31,10 +31,12 @@
|
|||
#include "script_text_editor.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/json.h"
|
||||
#include "core/math/expression.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "editor/debugger/editor_debugger_node.h"
|
||||
#include "editor/editor_command_palette.h"
|
||||
#include "editor/editor_help.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
|
|
@ -963,95 +965,88 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
|
|||
} else {
|
||||
EditorNode::get_singleton()->load_resource(symbol);
|
||||
}
|
||||
|
||||
} else if (lc_error == OK) {
|
||||
_goto_line(p_row);
|
||||
|
||||
switch (result.type) {
|
||||
case ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION: {
|
||||
if (result.script.is_valid()) {
|
||||
emit_signal(SNAME("request_open_script_at_line"), result.script, result.location - 1);
|
||||
} else {
|
||||
emit_signal(SNAME("request_save_history"));
|
||||
goto_line_centered(result.location - 1);
|
||||
}
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS: {
|
||||
emit_signal(SNAME("go_to_help"), "class_name:" + result.class_name);
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT: {
|
||||
StringName cname = result.class_name;
|
||||
bool success;
|
||||
while (true) {
|
||||
ClassDB::get_integer_constant(cname, result.class_member, &success);
|
||||
if (success) {
|
||||
result.class_name = cname;
|
||||
if (!result.class_name.is_empty() && EditorHelp::get_doc_data()->class_list.has(result.class_name)) {
|
||||
switch (result.type) {
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS: {
|
||||
emit_signal(SNAME("go_to_help"), "class_name:" + 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);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit_signal(SNAME("go_to_help"), "class_constant:" + result.class_name + ":" + result.class_member);
|
||||
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY: {
|
||||
emit_signal(SNAME("go_to_help"), "class_property:" + result.class_name + ":" + result.class_member);
|
||||
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD: {
|
||||
StringName cname = result.class_name;
|
||||
|
||||
while (true) {
|
||||
if (ClassDB::has_method(cname, result.class_member)) {
|
||||
result.class_name = cname;
|
||||
emit_signal(SNAME("go_to_help"), "class_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);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit_signal(SNAME("go_to_help"), "class_method:" + result.class_name + ":" + result.class_member);
|
||||
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS_SIGNAL: {
|
||||
StringName cname = result.class_name;
|
||||
|
||||
while (true) {
|
||||
if (ClassDB::has_signal(cname, result.class_member)) {
|
||||
result.class_name = cname;
|
||||
emit_signal(SNAME("go_to_help"), "class_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);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit_signal(SNAME("go_to_help"), "class_signal:" + result.class_name + ":" + result.class_member);
|
||||
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM: {
|
||||
StringName cname = result.class_name;
|
||||
StringName success;
|
||||
while (true) {
|
||||
success = ClassDB::get_integer_constant_enum(cname, result.class_member, true);
|
||||
if (success != StringName()) {
|
||||
result.class_name = cname;
|
||||
emit_signal(SNAME("go_to_help"), "class_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);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit_signal(SNAME("go_to_help"), "class_enum:" + result.class_name + ":" + result.class_member);
|
||||
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS_ANNOTATION: {
|
||||
emit_signal(SNAME("go_to_help"), "class_annotation:" + result.class_name + ":" + result.class_member);
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE: {
|
||||
emit_signal(SNAME("go_to_help"), "class_global:" + result.class_name + ":" + result.class_member);
|
||||
} break;
|
||||
default: {
|
||||
emit_signal(SNAME("go_to_help"), "class_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);
|
||||
}
|
||||
emit_signal(SNAME("go_to_help"), "class_enum:" + result.class_name + ":" + result.class_member);
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS_ANNOTATION: {
|
||||
emit_signal(SNAME("go_to_help"), "class_annotation:" + result.class_name + ":" + result.class_member);
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE: { // Deprecated.
|
||||
emit_signal(SNAME("go_to_help"), "class_global:" + result.class_name + ":" + result.class_member);
|
||||
} break;
|
||||
case ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION:
|
||||
case ScriptLanguage::LOOKUP_RESULT_LOCAL_CONSTANT:
|
||||
case ScriptLanguage::LOOKUP_RESULT_LOCAL_VARIABLE:
|
||||
case ScriptLanguage::LOOKUP_RESULT_MAX: {
|
||||
// Nothing to do.
|
||||
} break;
|
||||
}
|
||||
} else if (result.location >= 0) {
|
||||
if (result.script.is_valid()) {
|
||||
emit_signal(SNAME("request_open_script_at_line"), result.script, result.location - 1);
|
||||
} else {
|
||||
emit_signal(SNAME("request_save_history"));
|
||||
goto_line_centered(result.location - 1);
|
||||
}
|
||||
}
|
||||
} else if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) {
|
||||
|
|
@ -1102,6 +1097,109 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) {
|
|||
}
|
||||
}
|
||||
|
||||
void ScriptTextEditor::_show_symbol_tooltip(const String &p_symbol, int p_row, int p_column) {
|
||||
Node *base = get_tree()->get_edited_scene_root();
|
||||
if (base) {
|
||||
base = _find_node_for_script(base, base, script);
|
||||
}
|
||||
|
||||
ScriptLanguage::LookupResult result;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (!doc_symbol.is_empty()) {
|
||||
EditorHelpBitTooltip::show_tooltip(code_editor->get_text_editor(), doc_symbol, String(), true);
|
||||
}
|
||||
}
|
||||
|
||||
String ScriptTextEditor::_get_absolute_path(const String &rel_path) {
|
||||
String base_path = script->get_path().get_base_dir();
|
||||
String path = base_path.path_join(rel_path);
|
||||
|
|
@ -2235,6 +2333,7 @@ void ScriptTextEditor::_enable_code_editor() {
|
|||
code_editor->connect("validate_script", callable_mp(this, &ScriptTextEditor::_validate_script));
|
||||
code_editor->connect("load_theme_settings", callable_mp(this, &ScriptTextEditor::_load_theme_settings));
|
||||
code_editor->get_text_editor()->connect("symbol_lookup", callable_mp(this, &ScriptTextEditor::_lookup_symbol));
|
||||
code_editor->get_text_editor()->connect("symbol_hovered", callable_mp(this, &ScriptTextEditor::_show_symbol_tooltip));
|
||||
code_editor->get_text_editor()->connect("symbol_validate", callable_mp(this, &ScriptTextEditor::_validate_symbol));
|
||||
code_editor->get_text_editor()->connect("gutter_added", callable_mp(this, &ScriptTextEditor::_update_gutter_indexes));
|
||||
code_editor->get_text_editor()->connect("gutter_removed", callable_mp(this, &ScriptTextEditor::_update_gutter_indexes));
|
||||
|
|
@ -2411,6 +2510,7 @@ ScriptTextEditor::ScriptTextEditor() {
|
|||
update_settings();
|
||||
|
||||
code_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true);
|
||||
code_editor->get_text_editor()->set_symbol_tooltip_on_hover_enabled(true);
|
||||
code_editor->get_text_editor()->set_context_menu_enabled(false);
|
||||
|
||||
context_menu = memnew(PopupMenu);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue