Browse Source

Merge pull request #63728 from MarcusElg/%v

Add %v for formatting vectors
Rémi Verschelde 3 years ago
parent
commit
08d8f884cd
2 changed files with 164 additions and 5 deletions
  1. 72 3
      core/string/ustring.cpp
  2. 92 2
      tests/core/string/test_string.h

+ 72 - 3
core/string/ustring.cpp

@@ -4667,6 +4667,71 @@ String String::sprintf(const Array &values, bool *error) const {
 					in_format = false;
 					break;
 				}
+				case 'v': { // Vector2/3/4/2i/3i/4i
+					if (value_index >= values.size()) {
+						return "not enough arguments for format string";
+					}
+
+					int count;
+					switch (values[value_index].get_type()) {
+						case Variant::VECTOR2:
+						case Variant::VECTOR2I: {
+							count = 2;
+						} break;
+						case Variant::VECTOR3:
+						case Variant::VECTOR3I: {
+							count = 3;
+						} break;
+						case Variant::VECTOR4:
+						case Variant::VECTOR4I: {
+							count = 4;
+						} break;
+						default: {
+							return "%v requires a vector type (Vector2/3/4/2i/3i/4i)";
+						}
+					}
+
+					Vector4 vec = values[value_index];
+					String str = "(";
+					for (int i = 0; i < count; i++) {
+						double val = vec[i];
+						// Pad decimals out.
+						String number_str = String::num(ABS(val), min_decimals).pad_decimals(min_decimals);
+
+						int initial_len = number_str.length();
+
+						// Padding. Leave room for sign later if required.
+						int pad_chars_count = val < 0 ? min_chars - 1 : min_chars;
+						String pad_char = pad_with_zeros ? String("0") : String(" ");
+						if (left_justified) {
+							number_str = number_str.rpad(pad_chars_count, pad_char);
+						} else {
+							number_str = number_str.lpad(pad_chars_count, pad_char);
+						}
+
+						// Add sign if needed.
+						if (val < 0) {
+							if (left_justified) {
+								number_str = number_str.insert(0, "-");
+							} else {
+								number_str = number_str.insert(pad_with_zeros ? 0 : number_str.length() - initial_len, "-");
+							}
+						}
+
+						// Add number to combined string
+						str += number_str;
+
+						if (i < count - 1) {
+							str += ", ";
+						}
+					}
+					str += ")";
+
+					formatted += str;
+					++value_index;
+					in_format = false;
+					break;
+				}
 				case 's': { // String
 					if (value_index >= values.size()) {
 						return "not enough arguments for format string";
@@ -4759,7 +4824,7 @@ String String::sprintf(const Array &values, bool *error) const {
 					}
 					break;
 				}
-				case '.': { // Float separator.
+				case '.': { // Float/Vector separator.
 					if (in_decimals) {
 						return "too many decimal points in format";
 					}
@@ -4773,8 +4838,12 @@ String String::sprintf(const Array &values, bool *error) const {
 						return "not enough arguments for format string";
 					}
 
-					if (!values[value_index].is_num()) {
-						return "* wants number";
+					Variant::Type value_type = values[value_index].get_type();
+					if (!values[value_index].is_num() &&
+							value_type != Variant::VECTOR2 && value_type != Variant::VECTOR2I &&
+							value_type != Variant::VECTOR3 && value_type != Variant::VECTOR3I &&
+							value_type != Variant::VECTOR4 && value_type != Variant::VECTOR4I) {
+						return "* wants number or vector";
 					}
 
 					int size = values[value_index];

+ 92 - 2
tests/core/string/test_string.h

@@ -803,6 +803,96 @@ TEST_CASE("[String] sprintf") {
 	REQUIRE(error == false);
 	CHECK(output == String("fish -99.990000  frog"));
 
+	////// VECTORS
+
+	// Vector2
+	format = "fish %v frog";
+	args.clear();
+	args.push_back(Variant(Vector2(19.99, 1.00)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (19.990000, 1.000000) frog"));
+
+	// Vector3
+	format = "fish %v frog";
+	args.clear();
+	args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (19.990000, 1.000000, -2.050000) frog"));
+
+	// Vector4
+	format = "fish %v frog";
+	args.clear();
+	args.push_back(Variant(Vector4(19.99, 1.00, -2.05, 5.5)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (19.990000, 1.000000, -2.050000, 5.500000) frog"));
+
+	// Vector with negative values
+	format = "fish %v frog";
+	args.clear();
+	args.push_back(Variant(Vector2(-19.99, -1.00)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (-19.990000, -1.000000) frog"));
+
+	// Vector left-padded
+	format = "fish %11v frog";
+	args.clear();
+	args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (  19.990000,    1.000000,   -2.050000) frog"));
+
+	// Vector right-padded
+	format = "fish %-11v frog";
+	args.clear();
+	args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (19.990000  , 1.000000   , -2.050000  ) frog"));
+
+	// Vector left-padded with zeros
+	format = "fish %011v frog";
+	args.clear();
+	args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (0019.990000, 0001.000000, -002.050000) frog"));
+
+	// Vector given Vector3i.
+	format = "fish %v frog";
+	args.clear();
+	args.push_back(Variant(Vector3i(19, 1, -2)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (19.000000, 1.000000, -2.000000) frog"));
+
+	// Vector with 1 decimals.
+	format = "fish %.1v frog";
+	args.clear();
+	args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (20.0, 1.0, -2.0) frog"));
+
+	// Vector with 12 decimals.
+	format = "fish %.12v frog";
+	args.clear();
+	args.push_back(Variant(Vector3(19.00, 1.00, -2.00)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (19.000000000000, 1.000000000000, -2.000000000000) frog"));
+
+	// Vector with no decimals.
+	format = "fish %.v frog";
+	args.clear();
+	args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+	output = format.sprintf(args, &error);
+	REQUIRE(error == false);
+	CHECK(output == String("fish (20, 1, -2) frog"));
+
 	/////// Strings.
 
 	// String
@@ -920,14 +1010,14 @@ TEST_CASE("[String] sprintf") {
 	REQUIRE(error);
 	CHECK(output == "too many decimal points in format");
 
-	// * not a number
+	// * not a number or vector
 	format = "fish %*f frog";
 	args.clear();
 	args.push_back("cheese");
 	args.push_back(99.99);
 	output = format.sprintf(args, &error);
 	REQUIRE(error);
-	CHECK(output == "* wants number");
+	CHECK(output == "* wants number or vector");
 
 	// Character too long.
 	format = "fish %c frog";