Skip to content

Commit 1c9c19a

Browse files
authored
Simplify and standardize how data types are presented in user-facing strings (#4147)
* User-facing type formatting * Parse unicode not ASCII chars
1 parent 696b625 commit 1c9c19a

4 files changed

Lines changed: 84 additions & 32 deletions

File tree

editor/src/messages/portfolio/document/node_graph/node_properties.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ pub(crate) fn property_from_type(
276276
widgets.extend_from_slice(&[
277277
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
278278
TextLabel::new("-")
279-
.tooltip_label(format!("Data Type: {concrete_type}"))
279+
.tooltip_label(concrete_type.to_string())
280280
.tooltip_description("This data can only be supplied through the node graph because no widget exists for its type.")
281281
.widget_instance(),
282282
]);

editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ impl TypeSource {
9494
/// The type to display in the tooltip label.
9595
pub fn resolved_type_tooltip_string(&self) -> String {
9696
match self {
97-
TypeSource::Compiled(compiled_type) => format!("Data Type: {}", compiled_type.nested_type()),
98-
TypeSource::TaggedValue(value_type) => format!("Data Type: {}", value_type.nested_type()),
97+
TypeSource::Compiled(compiled_type) => compiled_type.nested_type().to_string(),
98+
TypeSource::TaggedValue(value_type) => value_type.nested_type().to_string(),
9999
TypeSource::Unknown => "Unknown Data Type".to_string(),
100100
TypeSource::Invalid => "Invalid Type Combination".to_string(),
101101
TypeSource::Error(_) => "Error Getting Data Type".to_string(),
@@ -253,8 +253,8 @@ impl NodeNetworkInterface {
253253
};
254254
let number_of_inputs = self.number_of_inputs(node_id, network_path);
255255
implementations
256-
.iter()
257-
.filter_map(|(node_io, _)| {
256+
.keys()
257+
.filter_map(|node_io| {
258258
// Check if this NodeIOTypes implementation is valid for the other inputs
259259
let valid_implementation = (0..number_of_inputs).filter(|iterator_index| iterator_index != input_index).all(|iterator_index| {
260260
let input_type = self.input_type_not_invalid(&InputConnector::node(*node_id, iterator_index), network_path);
@@ -293,8 +293,8 @@ impl NodeNetworkInterface {
293293
let valid_output_types = self.valid_output_types(&OutputConnector::node(*node_id, 0), network_path);
294294

295295
implementations
296-
.iter()
297-
.filter_map(|(node_io, _)| {
296+
.keys()
297+
.filter_map(|node_io| {
298298
if !valid_output_types.iter().any(|output_type| output_type.nested_type() == node_io.return_value.nested_type()) {
299299
return None;
300300
}

frontend/src/components/views/Graph.svelte

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,6 @@
188188
return `M-2,-2 L${nodeWidth + 2},-2 L${nodeWidth + 2},${nodeHeight + 2} L-2,${nodeHeight + 2}z ${rectangles.join(" ")}`;
189189
}
190190
191-
function dataTypeTooltipLabel(value: FrontendGraphInput | FrontendGraphOutput): string {
192-
return `Data Type: ${value.resolvedType}`;
193-
}
194-
195191
function nodeNameTooltipLabel(node: FrontendNode): string {
196192
return node.displayName === node.implementationName ? node.displayName : `${node.displayName} (${node.implementationName})`;
197193
}
@@ -349,7 +345,7 @@
349345
viewBox="0 0 8 8"
350346
class="connector"
351347
data-connector="output"
352-
data-tooltip-label={dataTypeTooltipLabel(frontendOutput)}
348+
data-tooltip-label={frontendOutput.resolvedType}
353349
data-tooltip-description={outputConnectedToText(frontendOutput)}
354350
data-datatype={frontendOutput.dataType}
355351
style:--data-color={`var(--color-data-${frontendOutput.dataType.toLowerCase()})`}
@@ -418,7 +414,7 @@
418414
viewBox="0 0 8 8"
419415
class="connector"
420416
data-connector="input"
421-
data-tooltip-label={dataTypeTooltipLabel(frontendInput)}
417+
data-tooltip-label={frontendInput.resolvedType}
422418
data-tooltip-description={inputConnectedToText(frontendInput)}
423419
data-datatype={frontendInput.dataType}
424420
style:--data-color={`var(--color-data-${frontendInput.dataType.toLowerCase()})`}
@@ -556,7 +552,7 @@
556552
viewBox="0 0 8 12"
557553
class="connector top"
558554
data-connector="output"
559-
data-tooltip-label={dataTypeTooltipLabel(node.primaryOutput)}
555+
data-tooltip-label={node.primaryOutput.resolvedType}
560556
data-tooltip-description={outputConnectedToText(node.primaryOutput)}
561557
data-datatype={node.primaryOutput.dataType}
562558
style:--data-color={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()})`}
@@ -578,7 +574,7 @@
578574
viewBox="0 0 8 12"
579575
class="connector bottom"
580576
data-connector="input"
581-
data-tooltip-label={node.primaryInput ? dataTypeTooltipLabel(node.primaryInput) : ""}
577+
data-tooltip-label={node.primaryInput ? node.primaryInput.resolvedType : ""}
582578
data-tooltip-description={node.primaryInput ? `${validTypesText(node.primaryInput).trim()}\n\n${inputConnectedToText(node.primaryInput)}` : ""}
583579
data-datatype={node.primaryInput?.dataType}
584580
style:--data-color={`var(--color-data-${(node.primaryInput?.dataType || "General").toLowerCase()})`}
@@ -601,7 +597,7 @@
601597
xmlns="http://www.w3.org/2000/svg"
602598
viewBox="0 0 8 8"
603599
class="connector"
604-
data-tooltip-label={dataTypeTooltipLabel(stackDataInput)}
600+
data-tooltip-label={stackDataInput.resolvedType}
605601
data-tooltip-description={`${validTypesText(stackDataInput).trim()}\n\n${inputConnectedToText(stackDataInput)}`}
606602
data-connector="input"
607603
data-datatype={stackDataInput.dataType}
@@ -755,7 +751,7 @@
755751
viewBox="0 0 8 8"
756752
class="connector primary-connector"
757753
data-connector="input"
758-
data-tooltip-label={dataTypeTooltipLabel(node.primaryInput)}
754+
data-tooltip-label={node.primaryInput.resolvedType}
759755
data-tooltip-description={`${validTypesText(node.primaryInput).trim()}\n\n${inputConnectedToText(node.primaryInput)}`}
760756
data-datatype={node.primaryInput?.dataType}
761757
style:--data-color={`var(--color-data-${node.primaryInput.dataType.toLowerCase()})`}
@@ -775,7 +771,7 @@
775771
viewBox="0 0 8 8"
776772
class="connector"
777773
data-connector="input"
778-
data-tooltip-label={dataTypeTooltipLabel(secondary)}
774+
data-tooltip-label={secondary.resolvedType}
779775
data-tooltip-description={`${validTypesText(secondary).trim()}\n\n${inputConnectedToText(secondary)}`}
780776
data-datatype={secondary.dataType}
781777
style:--data-color={`var(--color-data-${secondary.dataType.toLowerCase()})`}
@@ -798,7 +794,7 @@
798794
viewBox="0 0 8 8"
799795
class="connector primary-connector"
800796
data-connector="output"
801-
data-tooltip-label={dataTypeTooltipLabel(node.primaryOutput)}
797+
data-tooltip-label={node.primaryOutput.resolvedType}
802798
data-tooltip-description={`${outputConnectedToText(node.primaryOutput)}`}
803799
data-datatype={node.primaryOutput.dataType}
804800
style:--data-color={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()})`}
@@ -817,7 +813,7 @@
817813
viewBox="0 0 8 8"
818814
class="connector"
819815
data-connector="output"
820-
data-tooltip-label={dataTypeTooltipLabel(secondary)}
816+
data-tooltip-label={secondary.resolvedType}
821817
data-tooltip-description={`${outputConnectedToText(secondary)}`}
822818
data-datatype={secondary.dataType}
823819
style:--data-color={`var(--color-data-${secondary.dataType.toLowerCase()})`}

node-graph/libraries/core-types/src/types.rs

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::transform::Footprint;
21
use std::any::TypeId;
32
pub use std::borrow::Cow;
43
use std::fmt::{Display, Formatter};
@@ -346,8 +345,73 @@ pub fn simplify_identifier_name(ty: &str) -> String {
346345
.join("<")
347346
}
348347

348+
/// Converts a Rust-internal type name to its user-facing form.
349349
pub fn make_type_user_readable(ty: &str) -> String {
350-
ty.replace("Option<Arc<OwnedContextImpl>>", "Context").replace("Raster<CPU>", "Raster").replace("Raster<GPU>", "Raster")
350+
let ty = ty
351+
.replace("Option<Arc<OwnedContextImpl>>", "Context")
352+
.replace("Raster<CPU>", "Raster")
353+
.replace("Raster<GPU>", "Raster")
354+
.replace("DAffine2", "Transform")
355+
.replace("Affine2", "Transform")
356+
.replace("DVec2", "Vec2")
357+
.replace("IVec2", "Vec2")
358+
.replace("UVec2", "Vec2")
359+
.replace("&str", "String");
360+
361+
rewrite_list_as_array_brackets(&ty)
362+
}
363+
364+
/// Rewrites `List<T>` as `T[]`. Handles nesting (e.g. `List<List<Vector>>` becomes `Vector[][]`).
365+
/// Respects word boundaries so unrelated identifiers that happen to end in `List` are not affected.
366+
fn rewrite_list_as_array_brackets(input: &str) -> String {
367+
let bytes = input.as_bytes();
368+
let mut result = String::with_capacity(input.len());
369+
let mut i = 0;
370+
371+
while i < bytes.len() {
372+
let at_word_boundary = i == 0 || !is_identifier_byte(bytes[i - 1]);
373+
if at_word_boundary && bytes[i..].starts_with(b"List<") {
374+
let inner_start = i + b"List<".len();
375+
if let Some(close) = find_matching_angle_bracket(bytes, inner_start) {
376+
let inner = &input[inner_start..close];
377+
result.push_str(&rewrite_list_as_array_brackets(inner));
378+
result.push_str("[]");
379+
i = close + 1;
380+
continue;
381+
}
382+
}
383+
if bytes[i].is_ascii() {
384+
result.push(bytes[i] as char);
385+
i += 1;
386+
} else {
387+
let ch = input[i..].chars().next().unwrap();
388+
result.push(ch);
389+
i += ch.len_utf8();
390+
}
391+
}
392+
393+
result
394+
}
395+
396+
fn is_identifier_byte(byte: u8) -> bool {
397+
byte.is_ascii_alphanumeric() || byte == b'_'
398+
}
399+
400+
fn find_matching_angle_bracket(bytes: &[u8], start: usize) -> Option<usize> {
401+
let mut depth = 1_usize;
402+
for (offset, &byte) in bytes[start..].iter().enumerate() {
403+
match byte {
404+
b'<' => depth += 1,
405+
b'>' => {
406+
depth -= 1;
407+
if depth == 0 {
408+
return Some(start + offset);
409+
}
410+
}
411+
_ => {}
412+
}
413+
}
414+
None
351415
}
352416

353417
impl std::fmt::Debug for Type {
@@ -359,18 +423,10 @@ impl std::fmt::Debug for Type {
359423
// Display
360424
impl std::fmt::Display for Type {
361425
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
362-
use glam::*;
363-
364426
match self {
365427
Type::Generic(name) => write!(f, "{}", make_type_user_readable(name)),
366-
Type::Concrete(ty) => match () {
367-
() if self == &concrete!(DVec2) || self == &concrete!(Vec2) || self == &concrete!(IVec2) || self == &concrete!(UVec2) => write!(f, "Vec2"),
368-
() if self == &concrete!(glam::DAffine2) => write!(f, "Transform"),
369-
() if self == &concrete!(Footprint) => write!(f, "Footprint"),
370-
() if self == &concrete!(&str) || self == &concrete!(String) => write!(f, "String"),
371-
_ => write!(f, "{}", make_type_user_readable(&simplify_identifier_name(&ty.name))),
372-
},
373-
Type::Fn(call_arg, return_value) => write!(f, "{return_value} called with {call_arg}"),
428+
Type::Concrete(ty) => write!(f, "{ty}"),
429+
Type::Fn(_, return_value) => write!(f, "{return_value}"),
374430
Type::Future(ty) => write!(f, "{ty}"),
375431
}
376432
}

0 commit comments

Comments
 (0)