1 /++
2 String manipulation utilities needed by Godot-D
3 +/
4 module godot.util..string;
5 
6 import std.string, std.uni, std.utf;
7 import std.range, std.traits;
8 
9 /++
10 Convert snake_case or CONSTANT_CASE to D-style camelCase.
11 
12 Preserves leading underscore.
13 +/
14 nothrow
15 T snakeToCamel(T)(in T inputStr) if (isSomeString!T) {
16     Unqual!T str = inputStr;
17     alias Char = Unqual!(ElementEncodingType!T);
18     Char[] ret = [];
19 
20     bool newWord = false;
21     while (!str.empty) {
22         dchar c = str.decodeFront!(Yes.useReplacementDchar, Unqual!T);
23         if (c == '_') {
24             if (ret.empty)
25                 ret.encode!(Yes.useReplacementDchar)('_');
26             else
27                 newWord = true;
28         } else {
29             if (newWord) {
30                 ret.encode!(Yes.useReplacementDchar)(c.toUpper);
31                 newWord = false;
32             } else
33                 ret.encode!(Yes.useReplacementDchar)(c.toLower);
34         }
35     }
36     return ret;
37 }
38 
39 static assert("snake_case".snakeToCamel == "snakeCase");
40 static assert("_physics_process".snakeToCamel == "_physicsProcess", "_physics_process".snakeToCamel);
41 static assert("CONSTANT_CASE".snakeToCamel == "constantCase");
42 
43 /++
44 Convert camelCase to Godot-style snake_case.
45 
46 Preserves leading underscore.
47 +/
48 nothrow
49 T camelToSnake(T)(in T inputStr) if (isSomeString!T) {
50     Unqual!T str = inputStr;
51     alias Char = Unqual!(ElementEncodingType!T);
52     Char[] ret = [];
53 
54     bool inUppercaseWord = false;
55     while (!str.empty) {
56         dchar c = str.decodeFront!(Yes.useReplacementDchar);
57         if (c.isUpper) {
58             if (!ret.empty && !inUppercaseWord)
59                 ret.encode!(Yes.useReplacementDchar)('_');
60             ret.encode!(Yes.useReplacementDchar)(c.toLower);
61             inUppercaseWord = true;
62         } else {
63             ret.encode!(Yes.useReplacementDchar)(c);
64             inUppercaseWord = false;
65         }
66     }
67     // fix endings for Transform2D and 3D
68     ret = ret.replace("2_d", "2d").replace("3_d", "3d");
69     return ret;
70 }
71 
72 static assert("camelCase".camelToSnake == "camel_case");
73 static assert("_physicsProcess".camelToSnake == "_physics_process");
74 static assert("toUTF32".camelToSnake == "to_utf32");
75 static assert("Transform3D".camelToSnake == "transform3d");
76 static assert("Vector2i".camelToSnake == "vector2i");