Add stringify_variables method to misc.gd

This commit is contained in:
JeremyStar™ 2024-04-15 21:52:27 +02:00
parent 97703eac04
commit cacb5226bf
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
4 changed files with 170 additions and 1 deletions

@ -1 +1 @@
Subproject commit cdd49246684d446c0115bc5cfbca289eaa5fe354 Subproject commit 4cd4f12f95f61a27d493c783e367008452745e8c

View file

@ -45,6 +45,18 @@ class_name CoreConfiguration
@export var logui_background_color: Color @export var logui_background_color: Color
## What font size the graphical log should have. ## What font size the graphical log should have.
@export var logui_font_size: int @export var logui_font_size: int
@export_category("Miscellaneous")
## Shows or hides the type when calling [code]stringify_variables[/code].
@export var misc_stringify_show_type: bool
## Determines how [code]stringify_variables[/code] should display [class Color] variables.[br]
## Will display colors from [code]0[/code] to [code]255[/code] if [code]true[/code] or from [code]-1.0[/code] to [code]1.0[/code] if [code]false[/code].
@export var misc_stringify_color_range8: bool
## Determines if [class Array]s should be processed by [code]stringify_variables[/code].
@export var misc_stringify_array: bool
## Determines if [class Dictionary]s should be processed by [code]stringify_variables[/code].
@export var misc_stringify_dictionary: bool
@export_category("Easy Request Maker") @export_category("Easy Request Maker")
## Determines how unsecure requests should be handled. ## Determines how unsecure requests should be handled.
@export var erm_unsecure_requests: CoreTypes.BlockadeLevel @export var erm_unsecure_requests: CoreTypes.BlockadeLevel
@ -63,9 +75,17 @@ func _init() -> void:
logger_format = "%color%[%time%] [%level% %origin%] %message%" logger_format = "%color%[%time%] [%level% %origin%] %message%"
logger_newlines_override = true logger_newlines_override = true
logger_newlines_sizelimit = 40 logger_newlines_sizelimit = 40
# Log UI # Log UI
logui_enabled = true logui_enabled = true
logui_background_color = Color.BLACK # To disable the background, use Color.TRANSPARENT logui_background_color = Color.BLACK # To disable the background, use Color.TRANSPARENT
logui_font_size = 14 logui_font_size = 14
# Misc
misc_stringify_show_type = true
misc_stringify_color_range8 = true
misc_stringify_array = true
misc_stringify_dictionary = true
# Easy Request Maker # Easy Request Maker
erm_unsecure_requests = CoreTypes.BlockadeLevel.BLOCK erm_unsecure_requests = CoreTypes.BlockadeLevel.BLOCK

View file

@ -21,6 +21,19 @@
## and generally make your life as a developer easier. ## and generally make your life as a developer easier.
extends CoreBaseModule extends CoreBaseModule
# Configuration
var config_stringify_show_type: bool
var config_stringify_color_range8: bool
var config_stringify_array: bool
var config_stringify_dictionary: bool
# +++ module +++
func _pull_config() -> void:
config_stringify_show_type = core.config.misc_stringify_show_type
config_stringify_color_range8 = core.config.misc_stringify_color_range8
config_stringify_array = core.config.misc_stringify_array
config_stringify_dictionary = core.config.misc_stringify_dictionary
# +++ data type conversion +++ # +++ data type conversion +++
## Converts a number of bytes into mebibytes.[br] ## Converts a number of bytes into mebibytes.[br]
## [br] ## [br]
@ -125,6 +138,114 @@ func stringarray_to_array(array: Array[String]) -> Array:
func get_center(parent_size: Vector2, child_size: Vector2) -> Vector2: func get_center(parent_size: Vector2, child_size: Vector2) -> Vector2:
return Vector2(parent_size.x/2-child_size.x/2, parent_size.y/2-child_size.y/2) return Vector2(parent_size.x/2-child_size.x/2, parent_size.y/2-child_size.y/2)
## Makes variables as look correct inside strings.[br]
## Short examples:[br]
## [code]true[/code] -> [code]'true'[/code][br]
## [code]Vector2(69.064, PI)[/code] -> [code]'x=69.064 y=3.14159265358979'[/code][br]
## [code]"This is a test string"[/code] -> [code]'"This is a test string"'[/code][br]
## Full example:[br]
## [codeblock]
## Code:
## logger.diag(stringify_variables("Triggered %trigger% (pos=%position%, successful=%success%)", { "trigger": "shoot", "position": Vector2(5156.149, 581.69), "success": true }))
##
## Output:
## [16:44:35] [DIAG Test.gd] Triggered '"shoot"' (pos='x=5156.149 y=581.69', successful='true')
## [/codeblock]
func stringify_variables(template: String, variables: Dictionary, no_quotes: bool = false) -> String:
# To decrease allocations
var value
var type: String = ""
var replacement: String = ""
for placeholder in variables:
# Check key type
if typeof(placeholder) != TYPE_STRING:
logger.error("Invalid placeholder type '\"" + type_string(typeof(placeholder)) + "\", skipping")
continue
# Check for correct type
value = variables[placeholder]
match(typeof(value)):
# Primitives
Variant.Type.TYPE_NIL: replacement = "null"
Variant.Type.TYPE_BOOL: replacement = str(value)
Variant.Type.TYPE_INT: replacement = str(value)
Variant.Type.TYPE_FLOAT: replacement = str(value)
Variant.Type.TYPE_STRING: replacement = "\"" + value + "\""
Variant.Type.TYPE_STRING_NAME: replacement = "\"" + value + "\""
# Non-primitives
Variant.Type.TYPE_OBJECT: replacement = str(value)
Variant.Type.TYPE_COLOR:
if config_stringify_color_range8: replacement = "r=" + _sa(value.r8) + " g=" + _sa(value.g8) + " b=" + _sa(value.b8) + " a=" + _sa(value.a8)
else: replacement = "r=" + _sa(value.r) + " g=" + _sa(value.g) + " b=" + _sa(value.b) + " a=" + _sa(value.a)
Variant.Type.TYPE_RID: replacement = "id=" + _sa(value.get_id()) + " valid=" + _sa(value.is_valid())
Variant.Type.TYPE_ARRAY:
if config_stringify_array:
if value.size() == 0:
replacement = "[]"
else:
replacement = "[ "
for item in value:
if replacement == "[ ": replacement += _sa(item)
else: replacement += ", " + _sa(item)
replacement += " ]"
else: replacement = str(value)
Variant.Type.TYPE_DICTIONARY:
if config_stringify_dictionary:
if value.size() == 0: replacement = "{}"
else:
replacement = "{ "
for key in value:
if replacement == "{ ": replacement += _sa(key) + ": " + _sa(value[key])
else: replacement += ", " + _sa(key)
replacement += " }"
else: replacement = str(value)
# TODO: Packed Arrays
# Nodes & scripting
Variant.Type.TYPE_NODE_PATH: replacement = str(value)
Variant.Type.TYPE_CALLABLE: replacement = "valid=" + _sa(value.is_valid()) + " standard=" + _sa(value.is_standard()) + " object=" + _sa(value.get_object() ) + " method=" + value.get_method() + " args=" + _sa(value.get_bound_arguments())
Variant.Type.TYPE_SIGNAL: replacement = "name=" + _sa(value.get_name()) + " object=" + _sa(value.get_object())
# 2D
Variant.Type.TYPE_VECTOR2: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y)
Variant.Type.TYPE_VECTOR2I: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y)
Variant.Type.TYPE_RECT2: replacement = "size=" + _sa(value.size) + " pos=" + _sa(value.position) + " end=" + _sa(value.end)
Variant.Type.TYPE_RECT2I: replacement = "size=" + _sa(value.size) + " pos=" + _sa(value.position) + " end=" + _sa(value.end)
Variant.Type.TYPE_TRANSFORM2D: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " origin=" + _sa(value.origin)
# 3D
Variant.Type.TYPE_VECTOR3: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z)
Variant.Type.TYPE_VECTOR3I: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z)
Variant.Type.TYPE_PLANE: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " d=" + _sa(value.d) + " normal=" + _sa(value.normal)
Variant.Type.TYPE_QUATERNION: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " w=" + _sa(value.w)
Variant.Type.TYPE_AABB: replacement = "size=" + _sa(value.size) + " pos=" + _sa(value.position) + " end=" + _sa(value.end)
Variant.Type.TYPE_TRANSFORM3D: replacement = "basis=" + _sa(value.basis) + " origin=" + _sa(value.origin)
Variant.Type.TYPE_BASIS: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z)
Variant.Type.TYPE_PROJECTION: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " w=" + _sa(value.w)
# 4D
Variant.Type.TYPE_VECTOR4: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " w=" + _sa(value.w)
Variant.Type.TYPE_VECTOR4I: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " w=" + _sa(value.w)
# etc
Variant.Type.TYPE_MAX: replacement = str(value)
_:
replacement = str(value)
type = "(unknown) "
# Replace
if config_stringify_show_type and type == "":
match(typeof(value)):
Variant.Type.TYPE_NIL: type = ""
Variant.Type.TYPE_MAX: type = "(invalid) "
Variant.Type.TYPE_ARRAY:
if value.get_typed_builtin() != TYPE_NIL:
type = "(" + type_string(typeof(value)).to_lower() + "[" + type_string(typeof(value.get_typed_builtin())).to_lower() + "]) "
_: type = "(" + type_string(typeof(value)).to_lower() + ") " # something is causing almost everything to be displayed as a boolean, which is not true. i don't know what's the problem here however.
var quote: String = "'" if !no_quotes else ""
template = template.replace("%" + placeholder + "%", quote + type + replacement + quote)
return template
# Makes calls shorter
func _sa(value) -> String:
return stringify_variables("%var%", { "var": value }, true)
## Moved to [method Core.quit_safely]. ## Moved to [method Core.quit_safely].
## @deprecated ## @deprecated
func quit_safely(exitcode: int = 0) -> void: await core.quit_safely(exitcode) func quit_safely(exitcode: int = 0) -> void: await core.quit_safely(exitcode)

View file

@ -156,3 +156,31 @@ func test_get_center() -> void:
return return
rok() rok()
# stringify_variables
func test_stringify_variables() -> void:
rskip("Unfinished")
return
# Init CORE
await load_framework()
# Variables
var test_in_string: String = "[b]null[/b]=%null%\n[b]bool[/b]=%bool%\n[b]int[/b]=%int%\n[b]float[/b]=%float%\n[b]string[/b]=%string%\n[b]stringname[/b]=%stringname%\n[b]color[/b]=%color%\n[b]rid[/b]=%rid%\n[b]array[/b]=%array%\n[b]dict[/b]=%dictionary%\n[b]nodepath[/b]=%nodepath%\n[b]call[/b]=%callable%\n[b]signal[/b]=%signal%\n[b]vec2[/b]=%vector2%\n[b]vec2i[/b]=%vector2i%\n[b]rect2[/b]=%rect2%\n[b]rect2i[/b]=%rect2i%\n[b]trans2d[/b]=%transform2d%\n[b]vec3[/b]=%vector3%\n[b]vec3i[/b]=%vector3i%\n[b]plane[/b]=%plane%\n[b]quarternion[/b]=%quaternion%\n[b]aabb[/b]=%aabb%\n[b]trans3d[/b]=%transform3d%\n[b]basis[/b]=%basis%\n[b]projection[/b]=%projection%\n[b]vec4[/b]=%vector4%\n[b]vec4i[/b]=%vector4i%"
var test_in_args: Dictionary = { "null": null, "bool": true, "int": 505, "float": 505.69, "string": "some string", "stringname": "some string name", "color": Color("#d60532"), "rid": RenderingServer.get_white_texture(), "array": [ "item1", "item2", true, 4 ], "dictionary": { "key0": true, 1: "key2" }, "nodepath": NodePath("/root/CORE"), "callable": func() -> void: pass, "signal": core.logger.log_event, "vector2": Vector2(PI, TAU), "vector2i": Vector2i(505, 69), "rect2": Rect2(1.51, 2.56, 3.89, 4.11), "rect2i": Rect2i(1, 2, 3, 4), "transform2d": Transform2D(1.5, Vector2(2.1, 2.2), 3.6, Vector2(4.1, 4.2)), "vector3": Vector3(59.666, NAN, INF), "vector3i": Vector3i(505, 69, 1713208182), "plane": Plane(Vector3(1.5, 2.5, 3.5), 55.7777), "quaternion": Quaternion(1.55, 2.7812, 3.671, 4.8871), "aabb": AABB(Vector3(1.1, 1.2, 1.3), Vector3(2.1, 2.2, 2.3)), "transform3d": Transform3D(Basis(Vector3(1.11, 1.12, 1.13), Vector3(1.21, 1.22, 1.23), Vector3(1.31, 1.32, 1.33)), Vector3(2.1, 2.2, 2.3)), "basis": Basis(Vector3(1.1358, 1.268718, 1.35818), Vector3(2.1481, 2.258819, 2.3718), Vector3(3.1658581, 3.2581587, 3.357158)), "projection": Projection(Transform3D(Basis(Vector3(1.11, 1.12, 1.13), Vector3(1.21, 1.22, 1.23), Vector3(1.31, 1.32, 1.33)), Vector3(2.1, 2.2, 2.3))), "vector4": Vector4(1.55158, 2.517571, 3.58157, 4.51857185), "vector4i": Vector4i(1, 2, 3, 4) }
var test_out: String = "unfinished"
var test_result: String = core.misc.stringify_variables(test_in_string, test_in_args)
if test_result != test_out:
lerror("Got invalid test result:")
lerror("in (string) -> " + test_in_string.replace("\n", "\\n"))
await get_tree().create_timer(1).timeout # output overflow workaround
lerror("in (args) -> " + str(test_in_args))
await get_tree().create_timer(1).timeout # output overflow workaround
lerror("expected -> " + test_out.replace("\n", "\\n"))
await get_tree().create_timer(1).timeout # output overflow workaround
lerror("got -> " + test_result.replace("\n", "\\n"))
await get_tree().create_timer(1).timeout # output overflow workaround
rerror("Test did not return the right value (check logs)")
return
rok()