mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-28 15:39:57 +01:00
Adds proc to show variable type as string, adds this info to Varedit (#10442)
Adds a proc that prints the variable type, optionally with some extra info like text/list length, types, etc. Mostly useful for debugging. In this journey I found out that there are some types that are simply "undetectable"... Like filters, procs/callables, etc. Uses this in Varedit to make it slightly more clear which var is which. I played a lot with how it's displayed and it's kind of hard to make it visible enough but not distracting or taking up too much space. In the end I opted for a simple approach that just shows the short type and keeps varedit mostly untouched otherwise:
This commit is contained in:
@@ -891,6 +891,91 @@ var/list/wall_items = typecacheof(list(
|
||||
return 1
|
||||
return 0
|
||||
|
||||
// Returns a variable type as string, optionally with some details:
|
||||
// Objects (datums) get their type, paths get the type name, scalars show length (text) and value (numbers), lists show length.
|
||||
// Also attempts some detection of otherwise undetectable types using ref IDs
|
||||
var/global/known_proc = new /proc/get_type_ref_bytes
|
||||
/proc/get_debug_type(var/V, var/details = TRUE, var/print_numbers = TRUE, var/path_names = TRUE, var/text_lengths = TRUE, var/list_lengths = TRUE, var/show_useless_subtypes = TRUE)
|
||||
// scalars / basic types
|
||||
if(isnull(V))
|
||||
return "null"
|
||||
if(ispath(V))
|
||||
return details && path_names ? "path([V])" : "path"
|
||||
if(istext(V))
|
||||
return details && text_lengths ? "text([length(V) ])" : "text"
|
||||
if(isnum(V)) // Byond doesn't really differentiate between floats and ints, but we can sort of guess here
|
||||
// also technically we could also say that 0 and 1 are boolean but that'd be quite silly
|
||||
if(IsInteger(V) && V < 16777216 && V > -16777216)
|
||||
return details && print_numbers ? "int([V])" : "int"
|
||||
if(V >= INFINITY)
|
||||
return details ? "float(+INF)" : "float"
|
||||
if(V <= -INFINITY)
|
||||
return details ? "float(-INF)" : "float"
|
||||
return details && print_numbers ? "float([V])" : "float"
|
||||
// Resource types
|
||||
if(isicon(V))
|
||||
return "icon"
|
||||
if(isfile(V))
|
||||
return "file"
|
||||
// Types that don't inherit from /datum (note that /world is not here because you can't hold a reference to it)
|
||||
if(islist(V))
|
||||
return details && list_lengths ? "list([length(V)])" : "list"
|
||||
if(isclient(V))
|
||||
return "client"
|
||||
if(istype(V, /savefile))
|
||||
return "savefile"
|
||||
// Finally actual objects that inherit from /datum
|
||||
// We want to differentiate at least the basic "special" Byond types
|
||||
var/datum/D = V
|
||||
if(isarea(D))
|
||||
return details ? "area([D.type])" : "area"
|
||||
if(isturf(D))
|
||||
return details ? "turf([D.type])" : "turf"
|
||||
if(ismob(D))
|
||||
return details ? "mob([D.type])" : "mob"
|
||||
if(isobj(D))
|
||||
return details ? "obj([D.type])" : "obj"
|
||||
if(istype(D, /atom/movable)) // according to DM docs there should be no defined types under this but there certainly are some
|
||||
return details ? "movable([D.type])" : "movable"
|
||||
if(isatom(D))
|
||||
return details ? "atom([D.type])" : "atom"
|
||||
if(istype(D, /database))
|
||||
return details && show_useless_subtypes ? "database([D.type])" : "database"
|
||||
if(istype(D, /exception))
|
||||
return details && show_useless_subtypes ? "exception([D.type])" : "exception"
|
||||
if(istype(D, /mutable_appearance)) // must come before /image
|
||||
return details && show_useless_subtypes ? "mutable_appearance([D.type])" : "mutable_appearance"
|
||||
if(istype(D, /image))
|
||||
return details ? "image([D.type])" : "image"
|
||||
if(istype(D, /matrix))
|
||||
return details && show_useless_subtypes ? "matrix([D.type])" : "matrix"
|
||||
if(istype(D, /regex))
|
||||
return details && show_useless_subtypes ? "regex([D.type])" : "regex"
|
||||
if(istype(D, /sound))
|
||||
return details ? "sound([D.type])" : "sound"
|
||||
if(istype(D, /decl))
|
||||
return details ? "decl([D.type])" : "decl"
|
||||
if(isdatum(D))
|
||||
return details ? "datum([D.type])" : "datum"
|
||||
if(istype(D)) // let's future proof ourselves
|
||||
return details ? "unknown-object([D.type])" : "unknown-object"
|
||||
// some undetectable types
|
||||
var/refType = get_type_ref_bytes(V)
|
||||
if(refType == "")
|
||||
return "unknown"
|
||||
if(refType == get_type_ref_bytes(known_proc)) // it's a proc of some kind
|
||||
if(istext(V?:name) && V:name != "") // procs with names are generally verbs
|
||||
return "verb"
|
||||
return "proc"
|
||||
if(refType == "53")
|
||||
return "filters"
|
||||
if(refType == "3a")
|
||||
return "appearance"
|
||||
return "unknown-object([refType])" // If you see this you found a new undetectable type. Feel free to add it here.
|
||||
|
||||
/proc/get_type_ref_bytes(var/V) // returns first 4 bytes from \ref which denote the object type (for objects that is)
|
||||
return lowertext(copytext(ref(V), 4, 6))
|
||||
|
||||
/proc/format_text(text)
|
||||
return replacetext(replacetext(text,"\proper ",""),"\improper ","")
|
||||
|
||||
|
||||
@@ -37,8 +37,9 @@
|
||||
<title>[D] (\ref[D] - [D.type])</title>
|
||||
<style>
|
||||
body { font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; font-size: 10pt; }
|
||||
.key, .value { font-family: "Fira Code", Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-size: 9pt; }
|
||||
.key, .type, .value { font-family: "Fira Code", Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-size: 9pt; }
|
||||
.key { font-weight: bold }
|
||||
.type { text-decoration: underline; color: gray }
|
||||
</style>
|
||||
</head>
|
||||
<body onload='selectTextField(); updateSearch()'>
|
||||
@@ -50,7 +51,7 @@
|
||||
<td><div align='center'>[D.get_view_variables_header()]</div></td>
|
||||
</tr></table>
|
||||
<div align='center'>
|
||||
<b><font size='1'>[replacetext("[D.type]", "/", "/<wbr>")]</font></b>
|
||||
<b><font size='1'>[replacetext("[get_debug_type(D)]", "/", "/<wbr>")]</font></b>
|
||||
[holder.marked_datum == D ? "<br/><font size='1' color='red'><b>Marked Object</b></font>" : ""]
|
||||
</div>
|
||||
</td>
|
||||
@@ -124,10 +125,12 @@
|
||||
|
||||
/proc/make_view_variables_value(value, varname = "*")
|
||||
var/vtext = ""
|
||||
var/debug_type = get_debug_type(value, FALSE)
|
||||
var/extra = list()
|
||||
if(isnull(value))
|
||||
vtext = "null"
|
||||
// get_debug_type displays this
|
||||
else if(istext(value))
|
||||
debug_type = null // it's kinda annoying here; we can tell the type by the quotes
|
||||
vtext = "\"[value]\""
|
||||
else if(isicon(value))
|
||||
vtext = "[value]"
|
||||
@@ -144,7 +147,7 @@
|
||||
vtext = "<a href='?_src_=vars;Vars=\ref[C]'>\ref[C]</a> - [C] ([C.type])"
|
||||
else if(islist(value))
|
||||
var/list/L = value
|
||||
vtext = "/list ([L.len])"
|
||||
vtext = "([L.len])"
|
||||
if(!(varname in view_variables_dont_expand) && L.len > 0 && L.len < 100)
|
||||
extra += "<ul>"
|
||||
for (var/index = 1 to L.len)
|
||||
@@ -157,7 +160,7 @@
|
||||
else
|
||||
vtext = "[value]"
|
||||
|
||||
return "<span class=value>[vtext]</span>[jointext(extra, "")]"
|
||||
return "<span class=type>[debug_type]</span> <span class=value>[vtext]</span>[jointext(extra, "")]"
|
||||
|
||||
/proc/make_view_variables_var_entry(datum/D, varname, value, level=0)
|
||||
var/ecm = null
|
||||
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
author: Amunak
|
||||
delete-after: True
|
||||
changes:
|
||||
- admin: "Slightly improves varedit by adding the variable type to the display."
|
||||
Reference in New Issue
Block a user