Skip to content

Commit

Permalink
Add built-in GDScript keywords to the class reference
Browse files Browse the repository at this point in the history
These are part of `@GDScript` and appear in search results as part of
a new `builtin` documentable type. (`keyword` is not used, as `keywords`
is already the name of an optional attribute for most documentable types.)

Keywords can now be Ctrl + clicked in the script editor to go to their
class reference description.
  • Loading branch information
Calinou committed Sep 19, 2024
1 parent 694d3c2 commit 80db886
Show file tree
Hide file tree
Showing 17 changed files with 570 additions and 5 deletions.
17 changes: 17 additions & 0 deletions core/doc_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,7 @@ class DocData {
Vector<ConstantDoc> constants;
HashMap<String, EnumDoc> enums;
Vector<PropertyDoc> properties;
Vector<MethodDoc> builtins;
Vector<MethodDoc> annotations;
Vector<ThemeItemDoc> theme_properties;
bool is_deprecated = false;
Expand Down Expand Up @@ -810,6 +811,14 @@ class DocData {
doc.properties.push_back(PropertyDoc::from_dict(properties[i]));
}

Array builtins;
if (p_dict.has("builtins")) {
builtins = p_dict["builtins"];
}
for (int i = 0; i < builtins.size(); i++) {
doc.builtins.push_back(MethodDoc::from_dict(builtins[i]));
}

Array annotations;
if (p_dict.has("annotations")) {
annotations = p_dict["annotations"];
Expand Down Expand Up @@ -939,6 +948,14 @@ class DocData {
dict["properties"] = properties;
}

if (!p_doc.builtins.is_empty()) {
Array builtins;
for (int i = 0; i < p_doc.builtins.size(); i++) {
builtins.push_back(MethodDoc::to_dict(p_doc.builtins[i]));
}
dict["builtins"] = builtins;
}

if (!p_doc.annotations.is_empty()) {
Array annotations;
for (int i = 0; i < p_doc.annotations.size(); i++) {
Expand Down
2 changes: 2 additions & 0 deletions core/object/script_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ class ScriptLanguage : public Object {
LOOKUP_RESULT_CLASS_ENUM,
LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE,
LOOKUP_RESULT_CLASS_ANNOTATION,
LOOKUP_RESULT_CLASS_BUILTIN,
LOOKUP_RESULT_MAX
};

Expand Down Expand Up @@ -397,6 +398,7 @@ class ScriptLanguage : public Object {
/* LOADER FUNCTIONS */

virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
virtual void get_public_keywords(List<MethodInfo> *p_keywords) const = 0;
virtual void get_public_functions(List<MethodInfo> *p_functions) const = 0;
virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const = 0;
virtual void get_public_annotations(List<MethodInfo> *p_annotations) const = 0;
Expand Down
2 changes: 2 additions & 0 deletions core/object/script_language_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ void ScriptLanguageExtension::_bind_methods() {
GDVIRTUAL_BIND(_reload_tool_script, "script", "soft_reload");

GDVIRTUAL_BIND(_get_recognized_extensions);
GDVIRTUAL_BIND(_get_public_keywords);
GDVIRTUAL_BIND(_get_public_functions);
GDVIRTUAL_BIND(_get_public_constants);
GDVIRTUAL_BIND(_get_public_annotations);
Expand All @@ -171,6 +172,7 @@ void ScriptLanguageExtension::_bind_methods() {
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_ENUM);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_ANNOTATION);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_BUILTIN);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_MAX);

BIND_ENUM_CONSTANT(LOCATION_LOCAL);
Expand Down
10 changes: 10 additions & 0 deletions core/object/script_language_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,16 @@ class ScriptLanguageExtension : public ScriptLanguage {
}
}

GDVIRTUAL0RC(TypedArray<Dictionary>, _get_public_keywords)
virtual void get_public_keywords(List<MethodInfo> *p_keywords) const override {
TypedArray<Dictionary> ret;
GDVIRTUAL_REQUIRED_CALL(_get_public_keywords, ret);
for (const Variant &var : ret) {
MethodInfo mi = MethodInfo::from_dict(var);
p_keywords->push_back(mi);
}
}

GDVIRTUAL0RC(TypedArray<Dictionary>, _get_public_functions)
virtual void get_public_functions(List<MethodInfo> *p_functions) const override {
TypedArray<Dictionary> ret;
Expand Down
28 changes: 28 additions & 0 deletions doc/class.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,34 @@
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="builtins" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="builtin" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="param" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:sequence />
</xs:sequence>
<xs:attribute type="xs:byte" name="index" />
<xs:attribute type="xs:string" name="name" />
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="enum" use="optional" />
<xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
<xs:attribute type="xs:string" name="default" use="optional" />
</xs:complexType>
</xs:element>
<xs:element type="xs:string" name="description" />
</xs:sequence>
<xs:attribute type="xs:string" name="name" use="optional" />
<xs:attribute type="xs:string" name="keywords" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="annotations" minOccurs="0">
<xs:complexType>
<xs:sequence>
Expand Down
2 changes: 2 additions & 0 deletions doc/classes/ScriptEditor.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
class_signal:BaseButton:pressed
# Shows help for the CanvasItem property visible.
class_property:CanvasItem:visible
# Shows help for the GDScript built-in keyword.
class_builtin:@GDScript:for
# Shows help for the GDScript annotation export.
# Annotations should be prefixed with the `@` symbol in the descriptor, as shown here.
class_annotation:@GDScript:@export
Expand Down
9 changes: 8 additions & 1 deletion doc/classes/ScriptLanguageExtension.xml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@
<description>
</description>
</method>
<method name="_get_public_keywords" qualifiers="virtual const">
<return type="Dictionary[]" />
<description>
</description>
</method>
<method name="_get_recognized_extensions" qualifiers="virtual const">
<return type="PackedStringArray" />
<description>
Expand Down Expand Up @@ -391,7 +396,9 @@
</constant>
<constant name="LOOKUP_RESULT_CLASS_ANNOTATION" value="8" enum="LookupResultType">
</constant>
<constant name="LOOKUP_RESULT_MAX" value="9" enum="LookupResultType">
<constant name="LOOKUP_RESULT_CLASS_BUILTIN" value="9" enum="LookupResultType">
</constant>
<constant name="LOOKUP_RESULT_MAX" value="10" enum="LookupResultType">
</constant>
<constant name="LOCATION_LOCAL" value="0" enum="CodeCompletionLocation">
The option is local to the location of the code completion query - e.g. a local variable. Subsequent value of location represent options from the outer class, the exact value represent how far they are (in terms of inner classes).
Expand Down
42 changes: 42 additions & 0 deletions doc/tools/make_rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"Signals",
"Enumerations",
"Constants",
"Built-ins",
"Annotations",
"Property Descriptions",
"Constructor Descriptions",
Expand Down Expand Up @@ -603,6 +604,7 @@ def __init__(self, name: str) -> None:
self.methods: OrderedDict[str, List[MethodDef]] = OrderedDict()
self.operators: OrderedDict[str, List[MethodDef]] = OrderedDict()
self.signals: OrderedDict[str, SignalDef] = OrderedDict()
self.builtins: OrderedDict[str, List[AnnotationDef]] = OrderedDict()
self.annotations: OrderedDict[str, List[AnnotationDef]] = OrderedDict()
self.theme_items: OrderedDict[str, ThemeItemDef] = OrderedDict()
self.inherits: Optional[str] = None
Expand Down Expand Up @@ -1219,6 +1221,46 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:

f.write("\n\n")

# Built-in keyword descriptions
if len(class_def.builtins) > 0:
f.write(make_separator(True))
f.write(make_heading("Built-in keywords", "-"))

index = 0

for method_list in class_def.builtins.values(): # type: ignore
for i, m in enumerate(method_list):
if index != 0:
f.write(make_separator())

# Create builtin signature and anchor point.

self_link = ""
if i == 0:
builtin_anchor = f"class_{class_name}_builtin_{m.name}"
f.write(f".. _{builtin_anchor}:\n\n")
self_link = f" :ref:`🔗<{builtin_anchor}>`"

f.write(".. rst-class:: classref-builtin\n\n")

_, signature = make_method_signature(class_def, m, "", state)
f.write(f"{signature}{self_link}\n\n")

# Add builtin description, or a call to action if it's missing.

if m.description is not None and m.description.strip() != "":
f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
else:
f.write(".. container:: contribute\n\n\t")
f.write(
translate(
"There is currently no description for this built-in keyword. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
)
+ "\n\n"
)

index += 1

# Annotation descriptions
if len(class_def.annotations) > 0:
f.write(make_separator(True))
Expand Down
45 changes: 43 additions & 2 deletions editor/doc_tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ void DocTools::merge_from(const DocTools &p_data) {

merge_constants(c.constants, cf.constants);

merge_methods(c.builtins, cf.builtins);

merge_methods(c.annotations, cf.annotations);

merge_properties(c.properties, cf.properties);
Expand Down Expand Up @@ -1009,7 +1011,7 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
// Add scripting language built-ins.
{
// We only add a doc entry for languages which actually define any built-in
// methods, constants, or annotations.
// keywords (builtins), methods, constants, or annotations.
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptLanguage *lang = ScriptServer::get_language(i);
String cname = "@" + lang->get_name();
Expand Down Expand Up @@ -1063,6 +1065,39 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
c.constants.push_back(cd);
}

// Get keywords.
List<MethodInfo> binfo;
lang->get_public_keywords(&binfo);

for (const MethodInfo &bi : binfo) {
DocData::MethodDoc btd;
btd.name = bi.name;

if (bi.flags & METHOD_FLAG_VARARG) {
if (!btd.qualifiers.is_empty()) {
btd.qualifiers += " ";
}
btd.qualifiers += "vararg";
}

DocData::return_doc_from_retinfo(btd, bi.return_val);

int j = 0;
for (List<PropertyInfo>::ConstIterator itr = bi.arguments.begin(); itr != bi.arguments.end(); ++itr, ++j) {
DocData::ArgumentDoc ad;
DocData::argument_doc_from_arginfo(ad, *itr);

int darg_idx = j - (bi.arguments.size() - bi.default_arguments.size());
if (darg_idx >= 0) {
ad.default_value = DocData::get_default_value_string(bi.default_arguments[darg_idx]);
}

btd.arguments.push_back(ad);
}

c.builtins.push_back(btd);
}

// Get annotations.
List<MethodInfo> ainfo;
lang->get_public_annotations(&ainfo);
Expand Down Expand Up @@ -1097,11 +1132,12 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
}

// Skip adding the lang if it doesn't expose anything (e.g. C#).
if (c.methods.is_empty() && c.constants.is_empty() && c.annotations.is_empty()) {
if (c.methods.is_empty() && c.constants.is_empty() && c.builtins.is_empty() && c.annotations.is_empty()) {
continue;
}

c.methods.sort_custom<MethodCompare>();
c.builtins.sort_custom<MethodCompare>();
c.annotations.sort_custom<MethodCompare>();

class_list[cname] = c;
Expand Down Expand Up @@ -1350,6 +1386,9 @@ Error DocTools::_load(Ref<XMLParser> parser) {
} else if (name2 == "signals") {
Error err2 = _parse_methods(parser, c.signals);
ERR_FAIL_COND_V(err2, err2);
} else if (name2 == "builtins") {
Error err2 = _parse_methods(parser, c.builtins);
ERR_FAIL_COND_V(err2, err2);
} else if (name2 == "annotations") {
Error err2 = _parse_methods(parser, c.annotations);
ERR_FAIL_COND_V(err2, err2);
Expand Down Expand Up @@ -1741,6 +1780,8 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
_write_string(f, 1, "</constants>");
}

_write_method_doc(f, "builtin", c.builtins);

_write_method_doc(f, "annotation", c.annotations);

if (!c.theme_properties.is_empty()) {
Expand Down
Loading

0 comments on commit 80db886

Please sign in to comment.