mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
Add Options, Functions and Settings to convert Node-Names and Strings to kebab-case
- refactored and renamed String::_camelcase_to_underscore to String:_separate_compound_words - refactored String::to_snake_case to work with the refactored String::_separate_compound_words - created char_utils::is_hyphen to catch all hyphen variants in kebab-case conversion - created String::to_kebab_case using the new String::_separate_compound_words - created corresponding Documentation in String and StringName - simplified both switch statements in EditorNode and ProjectDialog - added new kebab-casing Option for Node Names in ProjectSettings - added missing camelCase Options to Scene- and Node-Names in ProjectSettings - simplified Mono RuntimeInterop Functions - hooked up the ConnectionsDialog - created additional Unit Tests
This commit is contained in:
parent
06c71fbf40
commit
bf963e767e
20 changed files with 195 additions and 114 deletions
|
|
@ -633,6 +633,7 @@ void ScriptLanguage::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_PASCAL_CASE);
|
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_PASCAL_CASE);
|
||||||
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_SNAKE_CASE);
|
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_SNAKE_CASE);
|
||||||
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_KEBAB_CASE);
|
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_KEBAB_CASE);
|
||||||
|
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_CAMEL_CASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) {
|
bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) {
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,7 @@ public:
|
||||||
SCRIPT_NAME_CASING_PASCAL_CASE,
|
SCRIPT_NAME_CASING_PASCAL_CASE,
|
||||||
SCRIPT_NAME_CASING_SNAKE_CASE,
|
SCRIPT_NAME_CASING_SNAKE_CASE,
|
||||||
SCRIPT_NAME_CASING_KEBAB_CASE,
|
SCRIPT_NAME_CASING_KEBAB_CASE,
|
||||||
|
SCRIPT_NAME_CASING_CAMEL_CASE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScriptTemplate {
|
struct ScriptTemplate {
|
||||||
|
|
|
||||||
|
|
@ -135,3 +135,7 @@ constexpr bool is_punct(char32_t p_char) {
|
||||||
constexpr bool is_underscore(char32_t p_char) {
|
constexpr bool is_underscore(char32_t p_char) {
|
||||||
return (p_char == '_');
|
return (p_char == '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool is_hyphen(char32_t p_char) {
|
||||||
|
return (p_char == '-') || (p_char == 0x2010) || (p_char == 0x2011);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -882,15 +882,15 @@ const char32_t *String::get_data() const {
|
||||||
return size() ? &operator[](0) : &zero;
|
return size() ? &operator[](0) : &zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
String String::_camelcase_to_underscore() const {
|
String String::_separate_compound_words() const {
|
||||||
const char32_t *cstr = get_data();
|
|
||||||
String new_string;
|
|
||||||
int start_index = 0;
|
|
||||||
|
|
||||||
if (length() == 0) {
|
if (length() == 0) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char32_t *cstr = get_data();
|
||||||
|
int start_index = 0;
|
||||||
|
String new_string;
|
||||||
|
|
||||||
bool is_prev_upper = is_unicode_upper_case(cstr[0]);
|
bool is_prev_upper = is_unicode_upper_case(cstr[0]);
|
||||||
bool is_prev_lower = is_unicode_lower_case(cstr[0]);
|
bool is_prev_lower = is_unicode_lower_case(cstr[0]);
|
||||||
bool is_prev_digit = is_digit(cstr[0]);
|
bool is_prev_digit = is_digit(cstr[0]);
|
||||||
|
|
@ -911,7 +911,7 @@ String String::_camelcase_to_underscore() const {
|
||||||
const bool cond_d = (is_prev_upper || is_prev_lower) && is_curr_digit; // A2, a2
|
const bool cond_d = (is_prev_upper || is_prev_lower) && is_curr_digit; // A2, a2
|
||||||
|
|
||||||
if (cond_a || cond_b || cond_c || cond_d) {
|
if (cond_a || cond_b || cond_c || cond_d) {
|
||||||
new_string += substr(start_index, i - start_index) + "_";
|
new_string += substr(start_index, i - start_index) + " ";
|
||||||
start_index = i;
|
start_index = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -921,40 +921,72 @@ String String::_camelcase_to_underscore() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
new_string += substr(start_index, size() - start_index);
|
new_string += substr(start_index, size() - start_index);
|
||||||
|
|
||||||
|
for (int i = 0; i < new_string.size(); i++) {
|
||||||
|
const bool whitespace = is_whitespace(new_string[i]);
|
||||||
|
const bool underscore = is_underscore(new_string[i]);
|
||||||
|
const bool hyphen = is_hyphen(new_string[i]);
|
||||||
|
|
||||||
|
if (whitespace || underscore || hyphen) {
|
||||||
|
new_string[i] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new_string.to_lower();
|
return new_string.to_lower();
|
||||||
}
|
}
|
||||||
|
|
||||||
String String::capitalize() const {
|
String String::capitalize() const {
|
||||||
String aux = _camelcase_to_underscore().replace_char('_', ' ').strip_edges();
|
String words = _separate_compound_words().strip_edges();
|
||||||
String cap;
|
String ret;
|
||||||
for (int i = 0; i < aux.get_slice_count(" "); i++) {
|
for (int i = 0; i < words.get_slice_count(" "); i++) {
|
||||||
String slice = aux.get_slicec(' ', i);
|
String slice = words.get_slicec(' ', i);
|
||||||
if (slice.length() > 0) {
|
if (slice.length() > 0) {
|
||||||
slice[0] = _find_upper(slice[0]);
|
slice[0] = _find_upper(slice[0]);
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
cap += " ";
|
ret += " ";
|
||||||
}
|
}
|
||||||
cap += slice;
|
ret += slice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
return cap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String String::to_camel_case() const {
|
String String::to_camel_case() const {
|
||||||
String s = to_pascal_case();
|
String words = _separate_compound_words().strip_edges();
|
||||||
if (!s.is_empty()) {
|
String ret;
|
||||||
s[0] = _find_lower(s[0]);
|
for (int i = 0; i < words.get_slice_count(" "); i++) {
|
||||||
|
String slice = words.get_slicec(' ', i);
|
||||||
|
if (slice.length() > 0) {
|
||||||
|
if (i == 0) {
|
||||||
|
slice[0] = _find_lower(slice[0]);
|
||||||
|
} else {
|
||||||
|
slice[0] = _find_upper(slice[0]);
|
||||||
}
|
}
|
||||||
return s;
|
ret += slice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
String String::to_pascal_case() const {
|
String String::to_pascal_case() const {
|
||||||
return capitalize().remove_char(' ');
|
String words = _separate_compound_words().strip_edges();
|
||||||
|
String ret;
|
||||||
|
for (int i = 0; i < words.get_slice_count(" "); i++) {
|
||||||
|
String slice = words.get_slicec(' ', i);
|
||||||
|
if (slice.length() > 0) {
|
||||||
|
slice[0] = _find_upper(slice[0]);
|
||||||
|
ret += slice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
String String::to_snake_case() const {
|
String String::to_snake_case() const {
|
||||||
return _camelcase_to_underscore().replace_char(' ', '_').strip_edges();
|
return _separate_compound_words().replace_char(' ', '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::to_kebab_case() const {
|
||||||
|
return _separate_compound_words().replace_char(' ', '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
String String::get_with_code_lines() const {
|
String String::get_with_code_lines() const {
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ class String {
|
||||||
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
|
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
|
||||||
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
|
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
|
||||||
int _count(const char *p_string, int p_from, int p_to, bool p_case_insensitive) const;
|
int _count(const char *p_string, int p_from, int p_to, bool p_case_insensitive) const;
|
||||||
String _camelcase_to_underscore() const;
|
String _separate_compound_words() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -454,6 +454,7 @@ public:
|
||||||
String to_camel_case() const;
|
String to_camel_case() const;
|
||||||
String to_pascal_case() const;
|
String to_pascal_case() const;
|
||||||
String to_snake_case() const;
|
String to_snake_case() const;
|
||||||
|
String to_kebab_case() const;
|
||||||
|
|
||||||
String get_with_code_lines() const;
|
String get_with_code_lines() const;
|
||||||
int get_slice_count(const String &p_splitter) const;
|
int get_slice_count(const String &p_splitter) const;
|
||||||
|
|
|
||||||
|
|
@ -1751,6 +1751,7 @@ static void _register_variant_builtin_methods_string() {
|
||||||
bind_string_method(to_camel_case, sarray(), varray());
|
bind_string_method(to_camel_case, sarray(), varray());
|
||||||
bind_string_method(to_pascal_case, sarray(), varray());
|
bind_string_method(to_pascal_case, sarray(), varray());
|
||||||
bind_string_method(to_snake_case, sarray(), varray());
|
bind_string_method(to_snake_case, sarray(), varray());
|
||||||
|
bind_string_method(to_kebab_case, sarray(), varray());
|
||||||
bind_string_methodv(split, static_cast<Vector<String> (String::*)(const String &, bool, int) const>(&String::split), sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
|
bind_string_methodv(split, static_cast<Vector<String> (String::*)(const String &, bool, int) const>(&String::split), sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
|
||||||
bind_string_methodv(rsplit, static_cast<Vector<String> (String::*)(const String &, bool, int) const>(&String::rsplit), sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
|
bind_string_methodv(rsplit, static_cast<Vector<String> (String::*)(const String &, bool, int) const>(&String::rsplit), sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
|
||||||
bind_string_method(split_floats, sarray("delimiter", "allow_empty"), varray(true));
|
bind_string_method(split_floats, sarray("delimiter", "allow_empty"), varray(true));
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,7 @@
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="SCRIPT_NAME_CASING_KEBAB_CASE" value="3" enum="ScriptNameCasing">
|
<constant name="SCRIPT_NAME_CASING_KEBAB_CASE" value="3" enum="ScriptNameCasing">
|
||||||
</constant>
|
</constant>
|
||||||
|
<constant name="SCRIPT_NAME_CASING_CAMEL_CASE" value="4" enum="ScriptNameCasing">
|
||||||
|
</constant>
|
||||||
</constants>
|
</constants>
|
||||||
</class>
|
</class>
|
||||||
|
|
|
||||||
|
|
@ -1040,6 +1040,25 @@
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="to_kebab_case" qualifiers="const">
|
||||||
|
<return type="String" />
|
||||||
|
<description>
|
||||||
|
Returns the string converted to [code]kebab-case[/code].
|
||||||
|
[b]Note:[/b] Numbers followed by a [i]single[/i] letter are not separated in the conversion to keep some words (such as "2D") together.
|
||||||
|
[codeblocks]
|
||||||
|
[gdscript]
|
||||||
|
"Node2D".to_kebab_case() # Returns "node-2d"
|
||||||
|
"2nd place".to_kebab_case() # Returns "2-nd-place"
|
||||||
|
"Texture3DAssetFolder".to_kebab_case() # Returns "texture-3d-asset-folder"
|
||||||
|
[/gdscript]
|
||||||
|
[csharp]
|
||||||
|
"Node2D".ToKebabCase(); // Returns "node-2d"
|
||||||
|
"2nd place".ToKebabCase(); // Returns "2-nd-place"
|
||||||
|
"Texture3DAssetFolder".ToKebabCase(); // Returns "texture-3d-asset-folder"
|
||||||
|
[/csharp]
|
||||||
|
[/codeblocks]
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="to_lower" qualifiers="const">
|
<method name="to_lower" qualifiers="const">
|
||||||
<return type="String" />
|
<return type="String" />
|
||||||
<description>
|
<description>
|
||||||
|
|
|
||||||
|
|
@ -948,6 +948,25 @@
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="to_kebab_case" qualifiers="const">
|
||||||
|
<return type="String" />
|
||||||
|
<description>
|
||||||
|
Returns the string converted to [code]kebab-case[/code].
|
||||||
|
[b]Note:[/b] Numbers followed by a [i]single[/i] letter are not separated in the conversion to keep some words (such as "2D") together.
|
||||||
|
[codeblocks]
|
||||||
|
[gdscript]
|
||||||
|
"Node2D".to_kebab_case() # Returns "node-2d"
|
||||||
|
"2nd place".to_kebab_case() # Returns "2-nd-place"
|
||||||
|
"Texture3DAssetFolder".to_kebab_case() # Returns "texture-3d-asset-folder"
|
||||||
|
[/gdscript]
|
||||||
|
[csharp]
|
||||||
|
"Node2D".ToKebabCase(); // Returns "node-2d"
|
||||||
|
"2nd place".ToKebabCase(); // Returns "2-nd-place"
|
||||||
|
"Texture3DAssetFolder".ToKebabCase(); // Returns "texture-3d-asset-folder"
|
||||||
|
[/csharp]
|
||||||
|
[/codeblocks]
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="to_lower" qualifiers="const">
|
<method name="to_lower" qualifiers="const">
|
||||||
<return type="String" />
|
<return type="String" />
|
||||||
<description>
|
<description>
|
||||||
|
|
|
||||||
|
|
@ -255,10 +255,12 @@ StringName ConnectDialog::generate_method_callback_name(Node *p_source, const St
|
||||||
subst["NodeName"] = node_name.to_pascal_case();
|
subst["NodeName"] = node_name.to_pascal_case();
|
||||||
subst["nodeName"] = node_name.to_camel_case();
|
subst["nodeName"] = node_name.to_camel_case();
|
||||||
subst["node_name"] = node_name.to_snake_case();
|
subst["node_name"] = node_name.to_snake_case();
|
||||||
|
subst["node-name"] = node_name.to_kebab_case();
|
||||||
|
|
||||||
subst["SignalName"] = p_signal_name.to_pascal_case();
|
subst["SignalName"] = p_signal_name.to_pascal_case();
|
||||||
subst["signalName"] = p_signal_name.to_camel_case();
|
subst["signalName"] = p_signal_name.to_camel_case();
|
||||||
subst["signal_name"] = p_signal_name.to_snake_case();
|
subst["signal_name"] = p_signal_name.to_snake_case();
|
||||||
|
subst["signal-name"] = p_signal_name.to_kebab_case();
|
||||||
|
|
||||||
String dst_method;
|
String dst_method;
|
||||||
if (p_source == p_target) {
|
if (p_source == p_target) {
|
||||||
|
|
|
||||||
|
|
@ -3374,11 +3374,13 @@ String EditorNode::adjust_scene_name_casing(const String &p_root_name) {
|
||||||
// Use casing of the root node.
|
// Use casing of the root node.
|
||||||
break;
|
break;
|
||||||
case SCENE_NAME_CASING_PASCAL_CASE:
|
case SCENE_NAME_CASING_PASCAL_CASE:
|
||||||
return p_root_name.replace_char('-', '_').to_pascal_case();
|
return p_root_name.to_pascal_case();
|
||||||
case SCENE_NAME_CASING_SNAKE_CASE:
|
case SCENE_NAME_CASING_SNAKE_CASE:
|
||||||
return p_root_name.replace_char('-', '_').to_snake_case();
|
return p_root_name.to_snake_case();
|
||||||
case SCENE_NAME_CASING_KEBAB_CASE:
|
case SCENE_NAME_CASING_KEBAB_CASE:
|
||||||
return p_root_name.to_snake_case().replace_char('_', '-');
|
return p_root_name.to_kebab_case();
|
||||||
|
case SCENE_NAME_CASING_CAMEL_CASE:
|
||||||
|
return p_root_name.to_camel_case();
|
||||||
}
|
}
|
||||||
return p_root_name;
|
return p_root_name;
|
||||||
}
|
}
|
||||||
|
|
@ -3395,11 +3397,13 @@ String EditorNode::adjust_script_name_casing(const String &p_file_name, ScriptLa
|
||||||
// Script language has no preference, so do not adjust.
|
// Script language has no preference, so do not adjust.
|
||||||
break;
|
break;
|
||||||
case ScriptLanguage::SCRIPT_NAME_CASING_PASCAL_CASE:
|
case ScriptLanguage::SCRIPT_NAME_CASING_PASCAL_CASE:
|
||||||
return p_file_name.replace_char('-', '_').to_pascal_case();
|
return p_file_name.to_pascal_case();
|
||||||
case ScriptLanguage::SCRIPT_NAME_CASING_SNAKE_CASE:
|
case ScriptLanguage::SCRIPT_NAME_CASING_SNAKE_CASE:
|
||||||
return p_file_name.replace_char('-', '_').to_snake_case();
|
return p_file_name.to_snake_case();
|
||||||
case ScriptLanguage::SCRIPT_NAME_CASING_KEBAB_CASE:
|
case ScriptLanguage::SCRIPT_NAME_CASING_KEBAB_CASE:
|
||||||
return p_file_name.to_snake_case().replace_char('_', '-');
|
return p_file_name.to_kebab_case();
|
||||||
|
case ScriptLanguage::SCRIPT_NAME_CASING_CAMEL_CASE:
|
||||||
|
return p_file_name.to_camel_case();
|
||||||
}
|
}
|
||||||
return p_file_name;
|
return p_file_name;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ public:
|
||||||
SCENE_NAME_CASING_PASCAL_CASE,
|
SCENE_NAME_CASING_PASCAL_CASE,
|
||||||
SCENE_NAME_CASING_SNAKE_CASE,
|
SCENE_NAME_CASING_SNAKE_CASE,
|
||||||
SCENE_NAME_CASING_KEBAB_CASE,
|
SCENE_NAME_CASING_KEBAB_CASE,
|
||||||
|
SCENE_NAME_CASING_CAMEL_CASE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ActionOnPlay {
|
enum ActionOnPlay {
|
||||||
|
|
|
||||||
|
|
@ -277,7 +277,7 @@ void ProjectDialog::_update_target_auto_dir() {
|
||||||
case 0: // No convention
|
case 0: // No convention
|
||||||
break;
|
break;
|
||||||
case 1: // kebab-case
|
case 1: // kebab-case
|
||||||
new_auto_dir = new_auto_dir.to_lower().replace_char(' ', '-');
|
new_auto_dir = new_auto_dir.to_kebab_case();
|
||||||
break;
|
break;
|
||||||
case 2: // snake_case
|
case 2: // snake_case
|
||||||
new_auto_dir = new_auto_dir.to_snake_case();
|
new_auto_dir = new_auto_dir.to_snake_case();
|
||||||
|
|
|
||||||
|
|
@ -279,8 +279,8 @@ void register_editor_types() {
|
||||||
|
|
||||||
GLOBAL_DEF("editor/naming/default_signal_callback_name", "_on_{node_name}_{signal_name}");
|
GLOBAL_DEF("editor/naming/default_signal_callback_name", "_on_{node_name}_{signal_name}");
|
||||||
GLOBAL_DEF("editor/naming/default_signal_callback_to_self_name", "_on_{signal_name}");
|
GLOBAL_DEF("editor/naming/default_signal_callback_to_self_name", "_on_{signal_name}");
|
||||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/scene_name_casing", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case,kebab-case"), EditorNode::SCENE_NAME_CASING_SNAKE_CASE);
|
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/scene_name_casing", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case,kebab-case,camelCase"), EditorNode::SCENE_NAME_CASING_SNAKE_CASE);
|
||||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/script_name_casing", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case,kebab-case"), ScriptLanguage::SCRIPT_NAME_CASING_AUTO);
|
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/script_name_casing", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case,kebab-case,camelCase"), ScriptLanguage::SCRIPT_NAME_CASING_AUTO);
|
||||||
|
|
||||||
GLOBAL_DEF("editor/import/reimport_missing_imported_files", true);
|
GLOBAL_DEF("editor/import/reimport_missing_imported_files", true);
|
||||||
GLOBAL_DEF("editor/import/use_multiple_threads", true);
|
GLOBAL_DEF("editor/import/use_multiple_threads", true);
|
||||||
|
|
|
||||||
|
|
@ -503,6 +503,9 @@ namespace Godot.NativeInterop
|
||||||
public static partial void godotsharp_string_simplify_path(scoped in godot_string p_self,
|
public static partial void godotsharp_string_simplify_path(scoped in godot_string p_self,
|
||||||
out godot_string r_simplified_path);
|
out godot_string r_simplified_path);
|
||||||
|
|
||||||
|
public static partial void godotsharp_string_capitalize(scoped in godot_string p_self,
|
||||||
|
out godot_string r_capitalized);
|
||||||
|
|
||||||
public static partial void godotsharp_string_to_camel_case(scoped in godot_string p_self,
|
public static partial void godotsharp_string_to_camel_case(scoped in godot_string p_self,
|
||||||
out godot_string r_camel_case);
|
out godot_string r_camel_case);
|
||||||
|
|
||||||
|
|
@ -512,6 +515,9 @@ namespace Godot.NativeInterop
|
||||||
public static partial void godotsharp_string_to_snake_case(scoped in godot_string p_self,
|
public static partial void godotsharp_string_to_snake_case(scoped in godot_string p_self,
|
||||||
out godot_string r_snake_case);
|
out godot_string r_snake_case);
|
||||||
|
|
||||||
|
public static partial void godotsharp_string_to_kebab_case(scoped in godot_string p_self,
|
||||||
|
out godot_string r_kebab_case);
|
||||||
|
|
||||||
// NodePath
|
// NodePath
|
||||||
|
|
||||||
public static partial void godotsharp_node_path_get_as_property_path(in godot_node_path p_self,
|
public static partial void godotsharp_node_path_get_as_property_path(in godot_node_path p_self,
|
||||||
|
|
|
||||||
|
|
@ -314,22 +314,10 @@ namespace Godot
|
||||||
/// <returns>The capitalized string.</returns>
|
/// <returns>The capitalized string.</returns>
|
||||||
public static string Capitalize(this string instance)
|
public static string Capitalize(this string instance)
|
||||||
{
|
{
|
||||||
string aux = instance.CamelcaseToUnderscore(true).Replace("_", " ", StringComparison.Ordinal).Trim();
|
using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
|
||||||
string cap = string.Empty;
|
NativeFuncs.godotsharp_string_capitalize(instanceStr, out godot_string capitalized);
|
||||||
|
using (capitalized)
|
||||||
for (int i = 0; i < aux.GetSliceCount(" "); i++)
|
return Marshaling.ConvertStringToManaged(capitalized);
|
||||||
{
|
|
||||||
string slice = aux.GetSliceCharacter(' ', i);
|
|
||||||
if (slice.Length > 0)
|
|
||||||
{
|
|
||||||
slice = char.ToUpperInvariant(slice[0]) + slice.Substring(1);
|
|
||||||
if (i > 0)
|
|
||||||
cap += " ";
|
|
||||||
cap += slice;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -371,49 +359,17 @@ namespace Godot
|
||||||
return Marshaling.ConvertStringToManaged(snakeCase);
|
return Marshaling.ConvertStringToManaged(snakeCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string CamelcaseToUnderscore(this string instance, bool lowerCase)
|
/// <summary>
|
||||||
|
/// Returns the string converted to <c>kebab-case</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance">The string to convert.</param>
|
||||||
|
/// <returns>The converted string.</returns>
|
||||||
|
public static string ToKebabCase(this string instance)
|
||||||
{
|
{
|
||||||
string newString = string.Empty;
|
using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
|
||||||
int startIndex = 0;
|
NativeFuncs.godotsharp_string_to_kebab_case(instanceStr, out godot_string kebabCase);
|
||||||
|
using (kebabCase)
|
||||||
for (int i = 1; i < instance.Length; i++)
|
return Marshaling.ConvertStringToManaged(kebabCase);
|
||||||
{
|
|
||||||
bool isUpper = char.IsUpper(instance[i]);
|
|
||||||
bool isNumber = char.IsDigit(instance[i]);
|
|
||||||
|
|
||||||
bool areNext2Lower = false;
|
|
||||||
bool isNextLower = false;
|
|
||||||
bool isNextNumber = false;
|
|
||||||
bool wasPrecedentUpper = char.IsUpper(instance[i - 1]);
|
|
||||||
bool wasPrecedentNumber = char.IsDigit(instance[i - 1]);
|
|
||||||
|
|
||||||
if (i + 2 < instance.Length)
|
|
||||||
{
|
|
||||||
areNext2Lower = char.IsLower(instance[i + 1]) && char.IsLower(instance[i + 2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i + 1 < instance.Length)
|
|
||||||
{
|
|
||||||
isNextLower = char.IsLower(instance[i + 1]);
|
|
||||||
isNextNumber = char.IsDigit(instance[i + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool condA = isUpper && !wasPrecedentUpper && !wasPrecedentNumber;
|
|
||||||
bool condB = wasPrecedentUpper && isUpper && areNext2Lower;
|
|
||||||
bool condC = isNumber && !wasPrecedentNumber;
|
|
||||||
bool canBreakNumberLetter = isNumber && !wasPrecedentNumber && isNextLower;
|
|
||||||
bool canBreakLetterNumber = !isNumber && wasPrecedentNumber && (isNextLower || isNextNumber);
|
|
||||||
|
|
||||||
bool shouldSplit = condA || condB || condC || canBreakNumberLetter || canBreakLetterNumber;
|
|
||||||
if (shouldSplit)
|
|
||||||
{
|
|
||||||
newString += string.Concat(instance.AsSpan(startIndex, i - startIndex), "_");
|
|
||||||
startIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newString += instance.Substring(startIndex, instance.Length - startIndex);
|
|
||||||
return lowerCase ? newString.ToLowerInvariant() : newString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1289,6 +1289,10 @@ void godotsharp_string_simplify_path(const String *p_self, String *r_simplified_
|
||||||
memnew_placement(r_simplified_path, String(p_self->simplify_path()));
|
memnew_placement(r_simplified_path, String(p_self->simplify_path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void godotsharp_string_capitalize(const String *p_self, String *r_capitalized) {
|
||||||
|
memnew_placement(r_capitalized, String(p_self->capitalize()));
|
||||||
|
}
|
||||||
|
|
||||||
void godotsharp_string_to_camel_case(const String *p_self, String *r_camel_case) {
|
void godotsharp_string_to_camel_case(const String *p_self, String *r_camel_case) {
|
||||||
memnew_placement(r_camel_case, String(p_self->to_camel_case()));
|
memnew_placement(r_camel_case, String(p_self->to_camel_case()));
|
||||||
}
|
}
|
||||||
|
|
@ -1301,6 +1305,10 @@ void godotsharp_string_to_snake_case(const String *p_self, String *r_snake_case)
|
||||||
memnew_placement(r_snake_case, String(p_self->to_snake_case()));
|
memnew_placement(r_snake_case, String(p_self->to_snake_case()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void godotsharp_string_to_kebab_case(const String *p_self, String *r_kebab_case) {
|
||||||
|
memnew_placement(r_kebab_case, String(p_self->to_kebab_case()));
|
||||||
|
}
|
||||||
|
|
||||||
void godotsharp_node_path_get_as_property_path(const NodePath *p_ptr, NodePath *r_dest) {
|
void godotsharp_node_path_get_as_property_path(const NodePath *p_ptr, NodePath *r_dest) {
|
||||||
memnew_placement(r_dest, NodePath(p_ptr->get_as_property_path()));
|
memnew_placement(r_dest, NodePath(p_ptr->get_as_property_path()));
|
||||||
}
|
}
|
||||||
|
|
@ -1700,9 +1708,11 @@ static const void *unmanaged_callbacks[]{
|
||||||
(void *)godotsharp_dictionary_get_typed_value_script,
|
(void *)godotsharp_dictionary_get_typed_value_script,
|
||||||
(void *)godotsharp_dictionary_to_string,
|
(void *)godotsharp_dictionary_to_string,
|
||||||
(void *)godotsharp_string_simplify_path,
|
(void *)godotsharp_string_simplify_path,
|
||||||
|
(void *)godotsharp_string_capitalize,
|
||||||
(void *)godotsharp_string_to_camel_case,
|
(void *)godotsharp_string_to_camel_case,
|
||||||
(void *)godotsharp_string_to_pascal_case,
|
(void *)godotsharp_string_to_pascal_case,
|
||||||
(void *)godotsharp_string_to_snake_case,
|
(void *)godotsharp_string_to_snake_case,
|
||||||
|
(void *)godotsharp_string_to_kebab_case,
|
||||||
(void *)godotsharp_node_path_get_as_property_path,
|
(void *)godotsharp_node_path_get_as_property_path,
|
||||||
(void *)godotsharp_node_path_get_concatenated_names,
|
(void *)godotsharp_node_path_get_concatenated_names,
|
||||||
(void *)godotsharp_node_path_get_concatenated_subnames,
|
(void *)godotsharp_node_path_get_concatenated_subnames,
|
||||||
|
|
|
||||||
|
|
@ -1641,6 +1641,8 @@ String Node::adjust_name_casing(const String &p_name) {
|
||||||
return p_name.to_camel_case();
|
return p_name.to_camel_case();
|
||||||
case NAME_CASING_SNAKE_CASE:
|
case NAME_CASING_SNAKE_CASE:
|
||||||
return p_name.to_snake_case();
|
return p_name.to_snake_case();
|
||||||
|
case NAME_CASING_KEBAB_CASE:
|
||||||
|
return p_name.to_kebab_case();
|
||||||
}
|
}
|
||||||
return p_name;
|
return p_name;
|
||||||
}
|
}
|
||||||
|
|
@ -3830,7 +3832,7 @@ RID Node::get_accessibility_element() const {
|
||||||
|
|
||||||
void Node::_bind_methods() {
|
void Node::_bind_methods() {
|
||||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"), 0);
|
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"), 0);
|
||||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"), NAME_CASING_PASCAL_CASE);
|
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case,kebab-case"), NAME_CASING_PASCAL_CASE);
|
||||||
|
|
||||||
ClassDB::bind_static_method("Node", D_METHOD("print_orphan_nodes"), &Node::print_orphan_nodes);
|
ClassDB::bind_static_method("Node", D_METHOD("print_orphan_nodes"), &Node::print_orphan_nodes);
|
||||||
ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false));
|
ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false));
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,8 @@ public:
|
||||||
enum NameCasing {
|
enum NameCasing {
|
||||||
NAME_CASING_PASCAL_CASE,
|
NAME_CASING_PASCAL_CASE,
|
||||||
NAME_CASING_CAMEL_CASE,
|
NAME_CASING_CAMEL_CASE,
|
||||||
NAME_CASING_SNAKE_CASE
|
NAME_CASING_SNAKE_CASE,
|
||||||
|
NAME_CASING_KEBAB_CASE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum InternalMode {
|
enum InternalMode {
|
||||||
|
|
|
||||||
|
|
@ -1451,6 +1451,14 @@ TEST_CASE("[String] Capitalize against many strings") {
|
||||||
output = "Snake Snake Case";
|
output = "Snake Snake Case";
|
||||||
CHECK(input.capitalize() == output);
|
CHECK(input.capitalize() == output);
|
||||||
|
|
||||||
|
input = "kebab-case";
|
||||||
|
output = "Kebab Case";
|
||||||
|
CHECK(input.capitalize() == output);
|
||||||
|
|
||||||
|
input = "kebab-kebab-case";
|
||||||
|
output = "Kebab Kebab Case";
|
||||||
|
CHECK(input.capitalize() == output);
|
||||||
|
|
||||||
input = "sha256sum";
|
input = "sha256sum";
|
||||||
output = "Sha 256 Sum";
|
output = "Sha 256 Sum";
|
||||||
CHECK(input.capitalize() == output);
|
CHECK(input.capitalize() == output);
|
||||||
|
|
@ -1471,6 +1479,14 @@ TEST_CASE("[String] Capitalize against many strings") {
|
||||||
output = "Snake Case Function( Snake Case Arg )";
|
output = "Snake Case Function( Snake Case Arg )";
|
||||||
CHECK(input.capitalize() == output);
|
CHECK(input.capitalize() == output);
|
||||||
|
|
||||||
|
input = "kebab-case-function( kebab-case-arg )";
|
||||||
|
output = "Kebab Case Function( Kebab Case Arg )";
|
||||||
|
CHECK(input.capitalize() == output);
|
||||||
|
|
||||||
|
input = "kebab_case_function( kebab_case_arg )";
|
||||||
|
output = "Kebab Case Function( Kebab Case Arg )";
|
||||||
|
CHECK(input.capitalize() == output);
|
||||||
|
|
||||||
input = U"словоСлово_слово слово";
|
input = U"словоСлово_слово слово";
|
||||||
output = U"Слово Слово Слово Слово";
|
output = U"Слово Слово Слово Слово";
|
||||||
CHECK(input.capitalize() == output);
|
CHECK(input.capitalize() == output);
|
||||||
|
|
@ -1489,35 +1505,37 @@ struct StringCasesTestCase {
|
||||||
const char32_t *camel_case;
|
const char32_t *camel_case;
|
||||||
const char32_t *pascal_case;
|
const char32_t *pascal_case;
|
||||||
const char32_t *snake_case;
|
const char32_t *snake_case;
|
||||||
|
const char32_t *kebab_case;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE("[String] Checking case conversion methods") {
|
TEST_CASE("[String] Checking case conversion methods") {
|
||||||
StringCasesTestCase test_cases[] = {
|
StringCasesTestCase test_cases[] = {
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
{ U"2D", U"2d", U"2d", U"2d" },
|
{ U"2D", U"2d", U"2d", U"2d", U"2d" },
|
||||||
{ U"2d", U"2d", U"2d", U"2d" },
|
{ U"2d", U"2d", U"2d", U"2d", U"2d" },
|
||||||
{ U"2db", U"2Db", U"2Db", U"2_db" },
|
{ U"2db", U"2Db", U"2Db", U"2_db", U"2-db" },
|
||||||
{ U"Vector3", U"vector3", U"Vector3", U"vector_3" },
|
{ U"Vector3", U"vector3", U"Vector3", U"vector_3", U"vector-3" },
|
||||||
{ U"sha256", U"sha256", U"Sha256", U"sha_256" },
|
{ U"sha256", U"sha256", U"Sha256", U"sha_256", U"sha-256" },
|
||||||
{ U"Node2D", U"node2d", U"Node2d", U"node_2d" },
|
{ U"Node2D", U"node2d", U"Node2d", U"node_2d", U"node-2d" },
|
||||||
{ U"RichTextLabel", U"richTextLabel", U"RichTextLabel", U"rich_text_label" },
|
{ U"RichTextLabel", U"richTextLabel", U"RichTextLabel", U"rich_text_label", U"rich-text-label" },
|
||||||
{ U"HTML5", U"html5", U"Html5", U"html_5" },
|
{ U"HTML5", U"html5", U"Html5", U"html_5", U"html-5" },
|
||||||
{ U"Node2DPosition", U"node2dPosition", U"Node2dPosition", U"node_2d_position" },
|
{ U"Node2DPosition", U"node2dPosition", U"Node2dPosition", U"node_2d_position", U"node-2d-position" },
|
||||||
{ U"Number2Digits", U"number2Digits", U"Number2Digits", U"number_2_digits" },
|
{ U"Number2Digits", U"number2Digits", U"Number2Digits", U"number_2_digits", U"number-2-digits" },
|
||||||
{ U"get_property_list", U"getPropertyList", U"GetPropertyList", U"get_property_list" },
|
{ U"get_property_list", U"getPropertyList", U"GetPropertyList", U"get_property_list", U"get-property-list" },
|
||||||
{ U"get_camera_2d", U"getCamera2d", U"GetCamera2d", U"get_camera_2d" },
|
{ U"get_camera_2d", U"getCamera2d", U"GetCamera2d", U"get_camera_2d", U"get-camera-2d" },
|
||||||
{ U"_physics_process", U"physicsProcess", U"PhysicsProcess", U"_physics_process" },
|
{ U"_physics_process", U"physicsProcess", U"PhysicsProcess", U"_physics_process", U"-physics-process" },
|
||||||
{ U"bytes2var", U"bytes2Var", U"Bytes2Var", U"bytes_2_var" },
|
{ U"bytes2var", U"bytes2Var", U"Bytes2Var", U"bytes_2_var", U"bytes-2-var" },
|
||||||
{ U"linear2db", U"linear2Db", U"Linear2Db", U"linear_2_db" },
|
{ U"linear2db", U"linear2Db", U"Linear2Db", U"linear_2_db", U"linear-2-db" },
|
||||||
{ U"sha256sum", U"sha256Sum", U"Sha256Sum", U"sha_256_sum" },
|
{ U"sha256sum", U"sha256Sum", U"Sha256Sum", U"sha_256_sum", U"sha-256-sum" },
|
||||||
{ U"camelCase", U"camelCase", U"CamelCase", U"camel_case" },
|
{ U"camelCase", U"camelCase", U"CamelCase", U"camel_case", U"camel-case" },
|
||||||
{ U"PascalCase", U"pascalCase", U"PascalCase", U"pascal_case" },
|
{ U"PascalCase", U"pascalCase", U"PascalCase", U"pascal_case", U"pascal-case" },
|
||||||
{ U"snake_case", U"snakeCase", U"SnakeCase", U"snake_case" },
|
{ U"snake_case", U"snakeCase", U"SnakeCase", U"snake_case", U"snake-case" },
|
||||||
{ U"Test TEST test", U"testTestTest", U"TestTestTest", U"test_test_test" },
|
{ U"kebab-case", U"kebabCase", U"KebabCase", U"kebab_case", U"kebab-case" },
|
||||||
{ U"словоСлово_слово слово", U"словоСловоСловоСлово", U"СловоСловоСловоСлово", U"слово_слово_слово_слово" },
|
{ U"Test TEST test", U"testTestTest", U"TestTestTest", U"test_test_test", U"test-test-test" },
|
||||||
{ U"λέξηΛέξη_λέξη λέξη", U"λέξηΛέξηΛέξηΛέξη", U"ΛέξηΛέξηΛέξηΛέξη", U"λέξη_λέξη_λέξη_λέξη" },
|
{ U"словоСлово_слово слово", U"словоСловоСловоСлово", U"СловоСловоСловоСлово", U"слово_слово_слово_слово", U"слово-слово-слово-слово" },
|
||||||
{ U"բառԲառ_բառ բառ", U"բառԲառԲառԲառ", U"ԲառԲառԲառԲառ", U"բառ_բառ_բառ_բառ" },
|
{ U"λέξηΛέξη_λέξη λέξη", U"λέξηΛέξηΛέξηΛέξη", U"ΛέξηΛέξηΛέξηΛέξη", U"λέξη_λέξη_λέξη_λέξη", U"λέξη-λέξη-λέξη-λέξη" },
|
||||||
{ nullptr, nullptr, nullptr, nullptr },
|
{ U"բառԲառ_բառ բառ", U"բառԲառԲառԲառ", U"ԲառԲառԲառԲառ", U"բառ_բառ_բառ_բառ", U"բառ-բառ-բառ-բառ" },
|
||||||
|
{ nullptr, nullptr, nullptr, nullptr, nullptr },
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1527,6 +1545,7 @@ TEST_CASE("[String] Checking case conversion methods") {
|
||||||
CHECK(input.to_camel_case() == test_cases[idx].camel_case);
|
CHECK(input.to_camel_case() == test_cases[idx].camel_case);
|
||||||
CHECK(input.to_pascal_case() == test_cases[idx].pascal_case);
|
CHECK(input.to_pascal_case() == test_cases[idx].pascal_case);
|
||||||
CHECK(input.to_snake_case() == test_cases[idx].snake_case);
|
CHECK(input.to_snake_case() == test_cases[idx].snake_case);
|
||||||
|
CHECK(input.to_kebab_case() == test_cases[idx].kebab_case);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue