Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tooltips for exported variables #35716

Open
wants to merge 1 commit into
base: 3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions core/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ struct PropertyInfo {
StringName class_name; //for classes
PropertyHint hint;
String hint_string;
#ifdef TOOLS_ENABLED
String tooltip;
#endif
uint32_t usage;

_FORCE_INLINE_ PropertyInfo added_usage(int p_fl) const {
Expand Down
2 changes: 1 addition & 1 deletion editor/editor_inspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,7 @@ void EditorInspector::update_tree() {
if (doc_hint != String()) {
ep->set_tooltip(property_prefix + p.name + "::" + doc_hint);
} else {
ep->set_tooltip(property_prefix + p.name);
ep->set_tooltip(property_prefix + p.name + "::" + p.tooltip);
}
ep->update_property();
ep->_update_pin_flags();
Expand Down
29 changes: 28 additions & 1 deletion modules/gdscript/gdscript_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3669,6 +3669,28 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
case GDScriptTokenizer::TK_CURSOR: {
tokenizer->advance();
} break;
case GDScriptTokenizer::TK_TOOLTIP: {
tokenizer->advance();
#ifdef TOOLS_ENABLED
if (tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type() == Variant::STRING) {
Variant constant = tokenizer->get_token_constant();
current_export.tooltip = constant;
}

// Handle multiline tooltips.
while (tokenizer->get_token(2) == GDScriptTokenizer::TK_TOOLTIP) {
tokenizer->advance(3);
if (tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type() == Variant::STRING) {
Variant constant = tokenizer->get_token_constant();
current_export.tooltip += constant.operator String();
}
}
#else
if (tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type() == Variant::STRING) {
tokenizer->advance();
}
#endif
} break;
case GDScriptTokenizer::TK_EOF:
p_class->end_line = tokenizer->get_token_line();
case GDScriptTokenizer::TK_ERROR: {
Expand Down Expand Up @@ -4846,7 +4868,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
member._export = current_export;
current_export = PropertyInfo();
}

#ifdef TOOLS_ENABLED
if (autoexport) {
member._export.tooltip = current_export.tooltip;
current_export.tooltip = "";
}
#endif
bool onready = tokenizer->get_token(-1) == GDScriptTokenizer::TK_PR_ONREADY;

tokenizer->advance();
Expand Down
89 changes: 87 additions & 2 deletions modules/gdscript/gdscript_tokenizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = {
"NAN",
"Error",
"EOF",
"Cursor"
"Cursor",
"##", // Tooltip comment for exported variables.
};

struct _bit {
Expand Down Expand Up @@ -258,6 +259,7 @@ bool GDScriptTokenizer::is_token_literal(int p_offset, bool variable_safe) const
case TK_PR_REMOTESYNC:
case TK_PR_MASTERSYNC:
case TK_PR_PUPPETSYNC:
case TK_TOOLTIP:
return true;

// Literal for non-variables only:
Expand Down Expand Up @@ -501,17 +503,100 @@ void GDScriptTokenizerText::_advance() {
#ifdef DEBUG_ENABLED
String comment;
#endif // DEBUG_ENABLED

#ifdef TOOLS_ENABLED
bool export_var = true;

if (GETCHAR(1) == '#' || GETCHAR(-1) == '#') {
// Check if it's a tooltip comment
int tip_code_pos = code_pos + 1;
bool multiline = false;
do {
// Move to the end of the line
while (tip_code_pos < len && _code[tip_code_pos] != '\n') {
tip_code_pos++;
}

// Skip '\n'
tip_code_pos++;

// Skip whitespaces
while (tip_code_pos < len && (_code[tip_code_pos] == ' ' || _code[tip_code_pos] == '\t' || _code[tip_code_pos] == '\r')) {
tip_code_pos++;
}

// Check if "##" -> possible multiline tooltip
if (tip_code_pos + 2 < len) {
if (_code[tip_code_pos] == '#' && _code[tip_code_pos + 1] == '#') {
multiline = true;
tip_code_pos += 2;
} else {
multiline = false;
}
} else {
multiline = false;
}
} while (multiline);

// "export" - 6 CharType characters
const int export_size = 6;

// Check if there is "export" keyword after "##" comments
if (tip_code_pos + export_size < len) {
const char *export_str = "export";
for (int e = 0; e < export_size; e++) {
if (_code[tip_code_pos + e] != export_str[e]) {
export_var = false;
break;
}
}
} else {
export_var = false;
}
} else {
export_var = false;
}

if (export_var) {
if (GETCHAR(1) == '#') {
_make_token(TK_TOOLTIP);
INCPOS(1);
return;
}
}

String tooltip_text;
#endif

while (GETCHAR(0) != '\n') {
#ifdef DEBUG_ENABLED
comment += GETCHAR(0);
#endif // DEBUG_ENABLED
code_pos++;

#ifdef TOOLS_ENABLED
if (export_var) {
tooltip_text += GETCHAR(0);
INCPOS(1);
} else
#endif
{
code_pos++;
}

if (GETCHAR(0) == 0) { //end of file
//_make_error("Unterminated Comment");
_make_token(TK_EOF);
return;
}
}

#ifdef TOOLS_ENABLED
if (export_var) {
_make_constant(tooltip_text.trim_prefix("#").trim_prefix(" "));
return;
}
#endif

#ifdef DEBUG_ENABLED
String comment_content = comment.trim_prefix("#").trim_prefix(" ");
if (comment_content.begins_with("warning-ignore:")) {
Expand Down
1 change: 1 addition & 0 deletions modules/gdscript/gdscript_tokenizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class GDScriptTokenizer {
TK_ERROR,
TK_EOF,
TK_CURSOR, //used for code completion
TK_TOOLTIP,
Copy link
Contributor

@ThakeeNathees ThakeeNathees Mar 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

creating a new token would break the parser unless every corner cases were handled.
ex: if TK_TOOLTIP inside a function (or just a comment starting with ##) the parser complains Expected end of statement after expression, got ... inside _parse_block()
and we check the next and previous tokens for parsing so we need to tell the parser that if it's a tool tip token just skip it.

TK_MAX
};

Expand Down