Merge pull request #78990 from RedMser/class-reference-keywords

Add search keywords to the class reference
This commit is contained in:
Rémi Verschelde 2024-02-12 13:33:12 +01:00
commit 62fcc7e5d3
No known key found for this signature in database
GPG key ID: C3336907360768E1
18 changed files with 176 additions and 42 deletions

View file

@ -117,6 +117,7 @@ public:
bool is_experimental = false;
Vector<ArgumentDoc> arguments;
Vector<int> errors_returned;
String keywords;
bool operator<(const MethodDoc &p_method) const {
if (name == p_method.name) {
// Must be an operator or a constructor since there is no other overloading
@ -195,6 +196,10 @@ public:
doc.errors_returned.push_back(errors_returned[i]);
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
return doc;
}
static Dictionary to_dict(const MethodDoc &p_doc) {
@ -225,6 +230,10 @@ public:
dict["is_experimental"] = p_doc.is_experimental;
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
if (!p_doc.arguments.is_empty()) {
Array arguments;
for (int i = 0; i < p_doc.arguments.size(); i++) {
@ -254,6 +263,7 @@ public:
String description;
bool is_deprecated = false;
bool is_experimental = false;
String keywords;
bool operator<(const ConstantDoc &p_const) const {
return name < p_const.name;
}
@ -291,6 +301,10 @@ public:
doc.is_experimental = p_dict["is_experimental"];
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
return doc;
}
static Dictionary to_dict(const ConstantDoc &p_doc) {
@ -319,6 +333,10 @@ public:
dict["is_experimental"] = p_doc.is_experimental;
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
return dict;
}
};
@ -335,6 +353,7 @@ public:
String overrides;
bool is_deprecated = false;
bool is_experimental = false;
String keywords;
bool operator<(const PropertyDoc &p_prop) const {
return name.naturalcasecmp_to(p_prop.name) < 0;
}
@ -388,6 +407,10 @@ public:
doc.is_experimental = p_dict["is_experimental"];
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
return doc;
}
static Dictionary to_dict(const PropertyDoc &p_doc) {
@ -432,6 +455,10 @@ public:
dict["is_experimental"] = p_doc.is_experimental;
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
return dict;
}
};
@ -442,6 +469,7 @@ public:
String data_type;
String description;
String default_value;
String keywords;
bool operator<(const ThemeItemDoc &p_theme_item) const {
// First sort by the data type, then by name.
if (data_type == p_theme_item.data_type) {
@ -472,6 +500,10 @@ public:
doc.default_value = p_dict["default_value"];
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
return doc;
}
static Dictionary to_dict(const ThemeItemDoc &p_doc) {
@ -497,6 +529,10 @@ public:
dict["default_value"] = p_doc.default_value;
}
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
return dict;
}
};
@ -573,6 +609,7 @@ public:
String inherits;
String brief_description;
String description;
String keywords;
Vector<TutorialDoc> tutorials;
Vector<MethodDoc> constructors;
Vector<MethodDoc> methods;
@ -609,6 +646,10 @@ public:
doc.description = p_dict["description"];
}
if (p_dict.has("keywords")) {
doc.keywords = p_dict["keywords"];
}
Array tutorials;
if (p_dict.has("tutorials")) {
tutorials = p_dict["tutorials"];
@ -816,6 +857,10 @@ public:
dict["script_path"] = p_doc.script_path;
}
if (!p_doc.keywords.is_empty()) {
dict["keywords"] = p_doc.keywords;
}
return dict;
}
};

View file

@ -101,6 +101,7 @@
<xs:attribute type="xs:string" name="qualifiers" use="optional" />
<xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
<xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
<xs:attribute type="xs:string" name="keywords" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
@ -123,6 +124,7 @@
<xs:attribute type="xs:string" name="default" use="optional" />
<xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
<xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
<xs:attribute type="xs:string" name="keywords" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
@ -144,6 +146,7 @@
<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="keywords" use="optional" />
</xs:complexType>
</xs:element>
<xs:element type="xs:string" name="description" />
@ -169,6 +172,7 @@
<xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
<xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
<xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
<xs:attribute type="xs:string" name="keywords" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
@ -209,6 +213,7 @@
</xs:sequence>
<xs:attribute type="xs:string" name="name" use="optional" />
<xs:attribute type="xs:string" name="qualifiers" use="optional" />
<xs:attribute type="xs:string" name="keywords" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
@ -225,6 +230,7 @@
<xs:attribute type="xs:string" name="data_type" />
<xs:attribute type="xs:string" name="type" />
<xs:attribute type="xs:string" name="default" use="optional" />
<xs:attribute type="xs:string" name="keywords" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
@ -275,6 +281,7 @@
<xs:attribute type="xs:string" name="inherits" />
<xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
<xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
<xs:attribute type="xs:string" name="keywords" use="optional" />
</xs:complexType>
</xs:element>
</xs:schema>

View file

@ -1080,7 +1080,7 @@
[b]Note:[/b] This function is called automatically when the project is run. If you need to fix the seed to have consistent, reproducible results, use [method seed] to initialize the random number generator.
</description>
</method>
<method name="remap">
<method name="remap" keywords="range, lerp">
<return type="float" />
<param index="0" name="value" type="float" />
<param index="1" name="istart" type="float" />

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Area2D" inherits="CollisionObject2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<class name="Area2D" inherits="CollisionObject2D" keywords="trigger" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A region of 2D space that detects other [CollisionObject2D]s entering or exiting it.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Area3D" inherits="CollisionObject3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<class name="Area3D" inherits="CollisionObject3D" keywords="trigger" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A region of 3D space that detects other [CollisionObject3D]s entering or exiting it.
</brief_description>

View file

@ -332,7 +332,7 @@
Returns the script associated with a typed array tied to a class name.
</description>
</method>
<method name="has" qualifiers="const">
<method name="has" qualifiers="const" keywords="includes, contains">
<return type="bool" />
<param index="0" name="value" type="Variant" />
<description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="DirAccess" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<class name="DirAccess" inherits="RefCounted" keywords="directory, path, folder" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Provides methods for managing directories and their content.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="InputEventMouseButton" inherits="InputEventMouse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<class name="InputEventMouseButton" inherits="InputEventMouse" keywords="click, press" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Represents a mouse button being pressed or released.
</brief_description>

View file

@ -722,7 +722,7 @@
Calls [method Object.notification] with [param what] on this node and all of its children, recursively.
</description>
</method>
<method name="queue_free">
<method name="queue_free" keywords="delete, remove, kill, die">
<return type="void" />
<description>
Queues this node to be deleted at the end of the current frame. When deleted, all of its children are deleted as well, and all references to the node and its children become invalid.

View file

@ -623,7 +623,7 @@
[b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot signals. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call.
</description>
</method>
<method name="free">
<method name="free" keywords="delete, remove, kill, die">
<return type="void" />
<description>
Deletes the object from memory. Pre-existing references to the object become invalid, and any attempt to access them will result in a run-time error. Checking the references with [method @GlobalScope.is_instance_valid] will return [code]false[/code].

View file

@ -88,7 +88,7 @@
Returns the [SceneState] representing the scene file contents.
</description>
</method>
<method name="instantiate" qualifiers="const">
<method name="instantiate" qualifiers="const" keywords="create, make, spawn, new">
<return type="Node" />
<param index="0" name="edit_state" type="int" enum="PackedScene.GenEditState" default="0" />
<description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PhysicalBone2D" inherits="RigidBody2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<class name="PhysicalBone2D" inherits="RigidBody2D" keywords="ragdoll" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [RigidBody2D]-derived node used to make [Bone2D]s in a [Skeleton2D] react to physics.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PhysicalBone3D" inherits="PhysicsBody3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<class name="PhysicalBone3D" inherits="PhysicsBody3D" keywords="ragdoll" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A physics body used to make bones in a [Skeleton3D] react to physics.
</brief_description>

View file

@ -41,7 +41,7 @@
</constructor>
</constructors>
<methods>
<method name="begins_with" qualifiers="const">
<method name="begins_with" qualifiers="const" keywords="starts_with">
<return type="bool" />
<param index="0" name="text" type="String" />
<description>
@ -126,7 +126,7 @@
[/codeblock]
</description>
</method>
<method name="contains" qualifiers="const">
<method name="contains" qualifiers="const" keywords="includes, has">
<return type="bool" />
<param index="0" name="what" type="String" />
<description>

View file

@ -166,6 +166,10 @@ class State:
if desc is not None and desc.text:
class_def.description = desc.text
keywords = class_root.get("keywords")
if keywords is not None:
class_def.keywords = keywords
properties = class_root.find("members")
if properties is not None:
for property in properties:
@ -564,6 +568,7 @@ class ClassDef(DefinitionBase):
self.brief_description: Optional[str] = None
self.description: Optional[str] = None
self.tutorials: List[Tuple[str, str]] = []
self.keywords: Optional[str] = None
# Used to match the class with XML source for output filtering purposes.
self.filepath: str = ""
@ -866,6 +871,10 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Remove the "Edit on Github" button from the online docs page.
f.write(":github_url: hide\n\n")
# Add keywords metadata.
if class_def.keywords is not None and class_def.keywords != "":
f.write(f".. meta::\n\t:keywords: {class_def.keywords}\n\n")
# Warn contributors not to edit this file directly.
# Also provide links to the source files for reference.

View file

@ -88,6 +88,7 @@ void DocTools::merge_from(const DocTools &p_data) {
c.is_deprecated = cf.is_deprecated;
c.is_experimental = cf.is_experimental;
c.keywords = cf.keywords;
c.description = cf.description;
c.brief_description = cf.brief_description;
@ -156,6 +157,7 @@ void DocTools::merge_from(const DocTools &p_data) {
m.description = mf.description;
m.is_deprecated = mf.is_deprecated;
m.is_experimental = mf.is_experimental;
m.keywords = mf.keywords;
break;
}
}
@ -172,6 +174,7 @@ void DocTools::merge_from(const DocTools &p_data) {
m.description = mf.description;
m.is_deprecated = mf.is_deprecated;
m.is_experimental = mf.is_experimental;
m.keywords = mf.keywords;
break;
}
}
@ -188,6 +191,7 @@ void DocTools::merge_from(const DocTools &p_data) {
m.description = mf.description;
m.is_deprecated = mf.is_deprecated;
m.is_experimental = mf.is_experimental;
m.keywords = mf.keywords;
break;
}
}
@ -204,6 +208,7 @@ void DocTools::merge_from(const DocTools &p_data) {
m.description = mf.description;
m.is_deprecated = mf.is_deprecated;
m.is_experimental = mf.is_experimental;
m.keywords = mf.keywords;
break;
}
}
@ -220,6 +225,7 @@ void DocTools::merge_from(const DocTools &p_data) {
p.description = pf.description;
p.is_deprecated = pf.is_deprecated;
p.is_experimental = pf.is_experimental;
p.keywords = pf.keywords;
break;
}
}
@ -234,6 +240,7 @@ void DocTools::merge_from(const DocTools &p_data) {
const DocData::ThemeItemDoc &pf = cf.theme_properties[j];
ti.description = pf.description;
ti.keywords = pf.keywords;
break;
}
}
@ -1067,6 +1074,9 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
if (parser->has_attribute("is_experimental")) {
method.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
if (parser->has_attribute("keywords")) {
method.keywords = parser->get_named_attribute_value("keywords");
}
while (parser->read() == OK) {
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
@ -1214,6 +1224,10 @@ Error DocTools::_load(Ref<XMLParser> parser) {
c.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
if (parser->has_attribute("keywords")) {
c.keywords = parser->get_named_attribute_value("keywords");
}
while (parser->read() == OK) {
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
String name2 = parser->get_node_name();
@ -1296,6 +1310,9 @@ Error DocTools::_load(Ref<XMLParser> parser) {
if (parser->has_attribute("is_experimental")) {
prop2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
if (parser->has_attribute("keywords")) {
prop2.keywords = parser->get_named_attribute_value("keywords");
}
if (!parser->is_empty()) {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@ -1326,6 +1343,9 @@ Error DocTools::_load(Ref<XMLParser> parser) {
prop2.type = parser->get_named_attribute_value("type");
ERR_FAIL_COND_V(!parser->has_attribute("data_type"), ERR_FILE_CORRUPT);
prop2.data_type = parser->get_named_attribute_value("data_type");
if (parser->has_attribute("keywords")) {
prop2.keywords = parser->get_named_attribute_value("keywords");
}
if (!parser->is_empty()) {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@ -1366,6 +1386,9 @@ Error DocTools::_load(Ref<XMLParser> parser) {
if (parser->has_attribute("is_experimental")) {
constant2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
if (parser->has_attribute("keywords")) {
constant2.keywords = parser->get_named_attribute_value("keywords");
}
if (!parser->is_empty()) {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@ -1410,20 +1433,21 @@ static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<Do
for (int i = 0; i < p_method_docs.size(); i++) {
const DocData::MethodDoc &m = p_method_docs[i];
String qualifiers;
if (!m.qualifiers.is_empty()) {
qualifiers += " qualifiers=\"" + m.qualifiers.xml_escape() + "\"";
}
String additional_attributes;
if (!m.qualifiers.is_empty()) {
additional_attributes += " qualifiers=\"" + m.qualifiers.xml_escape(true) + "\"";
}
if (m.is_deprecated) {
additional_attributes += " is_deprecated=\"true\"";
}
if (m.is_experimental) {
additional_attributes += " is_experimental=\"true\"";
}
if (!m.keywords.is_empty()) {
additional_attributes += String(" keywords=\"") + m.keywords.xml_escape(true) + "\"";
}
_write_string(f, 2, "<" + p_name + " name=\"" + m.name.xml_escape() + "\"" + qualifiers + additional_attributes + ">");
_write_string(f, 2, "<" + p_name + " name=\"" + m.name.xml_escape() + "\"" + additional_attributes + ">");
if (!m.return_type.is_empty()) {
String enum_text;
@ -1499,6 +1523,9 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
header += " is_experimental=\"true\"";
}
}
if (!c.keywords.is_empty()) {
header += String(" keywords=\"") + c.keywords.xml_escape(true) + "\"";
}
if (p_include_xml_schema) {
// Reference the XML schema so editors can provide error checking.
// Modules are nested deep, so change the path to reference the same schema everywhere.
@ -1552,6 +1579,9 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
if (c.properties[i].is_experimental) {
additional_attributes += " is_experimental=\"true\"";
}
if (!c.properties[i].keywords.is_empty()) {
additional_attributes += String(" keywords=\"") + c.properties[i].keywords.xml_escape(true) + "\"";
}
const DocData::PropertyDoc &p = c.properties[i];
@ -1580,6 +1610,9 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
if (c.constants[i].is_experimental) {
additional_attributes += " is_experimental=\"true\"";
}
if (!c.constants[i].keywords.is_empty()) {
additional_attributes += String(" keywords=\"") + c.constants[i].keywords.xml_escape(true) + "\"";
}
if (k.is_value_valid) {
if (!k.enumeration.is_empty()) {
@ -1614,11 +1647,15 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
for (int i = 0; i < c.theme_properties.size(); i++) {
const DocData::ThemeItemDoc &ti = c.theme_properties[i];
String additional_attributes;
if (!ti.default_value.is_empty()) {
_write_string(f, 2, "<theme_item name=\"" + ti.name + "\" data_type=\"" + ti.data_type + "\" type=\"" + ti.type + "\" default=\"" + ti.default_value.xml_escape(true) + "\">");
} else {
_write_string(f, 2, "<theme_item name=\"" + ti.name + "\" data_type=\"" + ti.data_type + "\" type=\"" + ti.type + "\">");
additional_attributes += String(" default=\"") + ti.default_value.xml_escape(true) + "\"";
}
if (!ti.keywords.is_empty()) {
additional_attributes += String(" keywords=\"") + ti.keywords.xml_escape(true) + "\"";
}
_write_string(f, 2, "<theme_item name=\"" + ti.name + "\" data_type=\"" + ti.data_type + "\" type=\"" + ti.type + "\"" + additional_attributes + ">");
_write_string(f, 3, _translate_doc_string(ti.description).strip_edges().xml_escape());

View file

@ -369,7 +369,7 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
// If the search term is empty, add any classes which are not script docs or which don't start with
// a double-quotation. This will ensure that only C++ classes and explicitly named classes will
// be added.
match.name = (term.is_empty() && (!class_doc->is_script_doc || class_doc->name[0] != '\"')) || _match_string(term, class_doc->name);
match.name = (term.is_empty() && (!class_doc->is_script_doc || class_doc->name[0] != '\"')) || _match_string(term, class_doc->name) || _match_keywords(term, class_doc->keywords);
}
// Match members only if the term is long enough, to avoid slow performance from building a large tree.
@ -386,35 +386,35 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
}
if (search_flags & SEARCH_SIGNALS) {
for (int i = 0; i < class_doc->signals.size(); i++) {
if (_all_terms_in_name(class_doc->signals[i].name)) {
if (_all_terms_in_name(class_doc->signals[i].name) || _all_terms_in_keywords(class_doc->signals[i].keywords)) {
match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc->signals[i]));
}
}
}
if (search_flags & SEARCH_CONSTANTS) {
for (int i = 0; i < class_doc->constants.size(); i++) {
if (_all_terms_in_name(class_doc->constants[i].name)) {
if (_all_terms_in_name(class_doc->constants[i].name) || _all_terms_in_keywords(class_doc->constants[i].keywords)) {
match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc->constants[i]));
}
}
}
if (search_flags & SEARCH_PROPERTIES) {
for (int i = 0; i < class_doc->properties.size(); i++) {
if (_all_terms_in_name(class_doc->properties[i].name)) {
if (_all_terms_in_name(class_doc->properties[i].name) || _all_terms_in_keywords(class_doc->properties[i].keywords)) {
match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc->properties[i]));
}
}
}
if (search_flags & SEARCH_THEME_ITEMS) {
for (int i = 0; i < class_doc->theme_properties.size(); i++) {
if (_all_terms_in_name(class_doc->theme_properties[i].name)) {
if (_all_terms_in_name(class_doc->theme_properties[i].name) || _all_terms_in_keywords(class_doc->theme_properties[i].keywords)) {
match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc->theme_properties[i]));
}
}
}
if (search_flags & SEARCH_ANNOTATIONS) {
for (int i = 0; i < class_doc->annotations.size(); i++) {
if (_match_string(term, class_doc->annotations[i].name)) {
if (_match_string(term, class_doc->annotations[i].name) || _all_terms_in_keywords(class_doc->annotations[i].keywords)) {
match.annotations.push_back(const_cast<DocData::MethodDoc *>(&class_doc->annotations[i]));
}
}
@ -574,7 +574,8 @@ void EditorHelpSearch::Runner::_match_method_name_and_push_back(Vector<DocData::
// Constructors, Methods, Operators...
for (int i = 0; i < p_methods.size(); i++) {
String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? p_methods[i].name : p_methods[i].name.to_lower();
if (_all_terms_in_name(method_name) ||
String keywords = (search_flags & SEARCH_CASE_SENSITIVE) ? p_methods[i].keywords : p_methods[i].keywords.to_lower();
if (_all_terms_in_name(method_name) || _all_terms_in_keywords(keywords) ||
(term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
(term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
(term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
@ -583,15 +584,24 @@ void EditorHelpSearch::Runner::_match_method_name_and_push_back(Vector<DocData::
}
}
bool EditorHelpSearch::Runner::_all_terms_in_name(String name) {
bool EditorHelpSearch::Runner::_all_terms_in_name(const String &p_name) const {
for (int i = 0; i < terms.size(); i++) {
if (!_match_string(terms[i], name)) {
if (!_match_string(terms[i], p_name)) {
return false;
}
}
return true;
}
bool EditorHelpSearch::Runner::_all_terms_in_keywords(const String &p_keywords) const {
for (const String &keyword : p_keywords.split(",")) {
if (_all_terms_in_name(keyword.strip_edges())) {
return true;
}
}
return false;
}
bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String &p_string) const {
if (search_flags & SEARCH_CASE_SENSITIVE) {
return p_string.find(p_term) > -1;
@ -600,7 +610,20 @@ bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String
}
}
void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_text) {
bool EditorHelpSearch::Runner::_match_keywords(const String &p_term, const String &p_keywords) const {
for (const String &keyword : p_keywords.split(",")) {
if (_match_string(p_term, keyword.strip_edges())) {
return true;
}
}
return false;
}
void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_text, bool p_is_keywords) {
if (p_text.is_empty()) {
return;
}
float inverse_length = 1.f / float(p_text.length());
// Favor types where search term is a substring close to the start of the type.
@ -612,6 +635,11 @@ void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_tex
w = 0.1f;
score *= (1 - w) + w * (term.length() * inverse_length);
// Reduce the score of keywords, since they are an indirect match.
if (p_is_keywords) {
score *= 0.9f;
}
if (match_highest_score == 0 || score > match_highest_score) {
matched_item = p_item;
match_highest_score = score;
@ -711,43 +739,46 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const
}
_match_item(item, p_doc->name);
for (const String &keyword : p_doc->keywords.split(",")) {
_match_item(item, keyword.strip_edges(), true);
}
return item;
}
TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) {
String tooltip = _build_method_tooltip(p_class_doc, p_doc);
return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) {
String tooltip = _build_method_tooltip(p_class_doc, p_doc);
return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) {
String tooltip = _build_method_tooltip(p_class_doc, p_doc);
return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_doc->name, p_text, TTRC("Annotation"), "annotation", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_doc->name, p_text, TTRC("Annotation"), "annotation", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) {
String tooltip = p_class_doc->name + "." + p_doc->name;
return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) {
String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name;
tooltip += "\n " + p_class_doc->name + "." + p_doc->setter + "(value) setter";
tooltip += "\n " + p_class_doc->name + "." + p_doc->getter + "() getter";
return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, p_doc->name, TTRC("Property"), "property", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, p_doc->name, TTRC("Property"), "property", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc) {
String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name;
return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, p_doc->name, TTRC("Theme Property"), "theme_item", tooltip, false, false);
return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, p_doc->name, TTRC("Theme Property"), "theme_item", p_doc->keywords, tooltip, false, false);
}
TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, bool is_deprecated, bool is_experimental) {
TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool is_deprecated, bool is_experimental) {
const String item_meta = "class_" + p_metatype + ":" + p_class_name + ":" + p_name;
TreeItem *item = nullptr;
@ -774,6 +805,9 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons
}
_match_item(item, p_name);
for (const String &keyword : p_keywords.split(",")) {
_match_item(item, keyword.strip_edges(), true);
}
return item;
}

View file

@ -160,9 +160,11 @@ class EditorHelpSearch::Runner : public RefCounted {
String _build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const;
void _match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, Vector<DocData::MethodDoc *> *r_match_methods);
bool _all_terms_in_name(String name);
bool _all_terms_in_name(const String &p_name) const;
bool _all_terms_in_keywords(const String &p_name) const;
bool _match_string(const String &p_term, const String &p_string) const;
void _match_item(TreeItem *p_item, const String &p_text);
bool _match_keywords(const String &p_term, const String &p_keywords) const;
void _match_item(TreeItem *p_item, const String &p_text, bool p_is_keywords = false);
TreeItem *_create_class_hierarchy(const ClassMatch &p_match);
TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray);
TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc);
@ -171,7 +173,7 @@ class EditorHelpSearch::Runner : public RefCounted {
TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc);
TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc);
TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc);
TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, bool is_deprecated, bool is_experimental);
TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool is_deprecated, bool is_experimental);
public:
bool work(uint64_t slot = 100000);