diff --git a/flake-info/src/data/import.rs b/flake-info/src/data/import.rs index 9874446..ad195d4 100644 --- a/flake-info/src/data/import.rs +++ b/flake-info/src/data/import.rs @@ -145,7 +145,7 @@ impl Serialize for DocValue { md.to_owned() })) } - DocValue::Value(v) => serializer.serialize_str(&print_value(v.to_owned())), + DocValue::Value(v) => serializer.serialize_str(&print_value(v)), } } } diff --git a/flake-info/src/data/prettyprint.rs b/flake-info/src/data/prettyprint.rs index 8270815..77d2248 100644 --- a/flake-info/src/data/prettyprint.rs +++ b/flake-info/src/data/prettyprint.rs @@ -15,11 +15,24 @@ impl Display for Indent { } } -pub fn print_value(value: Value) -> String { +pub fn print_value(value: &Value) -> String { print_value_indent(value, Indent(0)) } -fn print_value_indent(value: Value, indent: Indent) -> String { +/// Formats an attrset key by adding quotes when necessary +fn format_attrset_key(key: &str) -> String { + if key.contains("/") + || key.contains(" ") + || key.is_empty() + || (b'0'..=b'9').contains(&key.as_bytes()[0]) + { + format!("{:?}", key) + } else { + key.to_string() + } +} + +fn print_value_indent(value: &Value, indent: Indent) -> String { match value { Value::Null => "null".to_owned(), Value::Bool(b) => format!("{}", b), @@ -44,6 +57,14 @@ fn print_value_indent(value: Value, indent: Indent) -> String { if a.is_empty() { return "[ ]".to_owned(); } + if a.len() == 1 { + // Return early if the wrapped value fits on one line + let val = print_value(a.first().unwrap()); + if !val.contains("\n") { + return format!("[ {} ]", val); + } + } + let items = a .into_iter() .map(|v| print_value_indent(v, indent.next())) @@ -63,9 +84,26 @@ fn print_value_indent(value: Value, indent: Indent) -> String { if o.is_empty() { return "{ }".to_owned(); } + if o.len() == 1 { + // Return early if the wrapped value fits on one line + let val = print_value(o.values().next().unwrap()); + if !val.contains("\n") { + return format!( + "{{ {} = {}; }}", + format_attrset_key(o.keys().next().unwrap()), + val + ); + } + } let items = o .into_iter() - .map(|(k, v)| format!("{} = {}", k, print_value_indent(v, indent.next()))) + .map(|(k, v)| { + format!( + "{} = {}", + format_attrset_key(&k), + print_value_indent(v, indent.next()) + ) + }) .collect::>() .join(&format!(";\n{}", indent.next())); @@ -90,7 +128,7 @@ mod tests { #[test] fn test_string() { let json = json!("Hello World"); - assert_eq!(print_value(json), "\"Hello World\""); + assert_eq!(print_value(&json), "\"Hello World\""); } #[test] @@ -101,7 +139,7 @@ World !!!"# ); assert_eq!( - print_value(json), + print_value(&json), r#"'' Hello World @@ -113,26 +151,46 @@ World #[test] fn test_num() { let json = json!(1); - assert_eq!(print_value(json), "1"); + assert_eq!(print_value(&json), "1"); } #[test] fn test_bool() { let json = json!(true); - assert_eq!(print_value(json), "true"); + assert_eq!(print_value(&json), "true"); } #[test] fn test_empty_list() { let json = json!([]); - assert_eq!(print_value(json), "[ ]"); + assert_eq!(print_value(&json), "[ ]"); + } + + #[test] + fn test_list_one_item() { + let json = json!([1]); + assert_eq!(print_value(&json), "[ 1 ]"); + } + + #[test] + fn test_list_one_multiline_item() { + let json = json!(["first line\nsecond line"]); + assert_eq!( + print_value(&json), + r#"[ + '' + first line + second line + '' +]"# + ); } #[test] fn test_filled_list() { let json = json!([1, "hello", true, null]); assert_eq!( - print_value(json), + print_value(&json), r#"[ 1 "hello" @@ -145,15 +203,42 @@ World #[test] fn test_empty_set() { let json = json!({}); - assert_eq!(print_value(json), "{ }"); + assert_eq!(print_value(&json), "{ }"); + } + + #[test] + fn test_set_one_item() { + let json = json!({ "hello": "world" }); + assert_eq!(print_value(&json), "{ hello = \"world\"; }"); + } + + #[test] + fn test_set_number_key() { + let json = json!({ "1hello": "world" }); + assert_eq!(print_value(&json), "{ \"1hello\" = \"world\"; }"); + } + + #[test] + fn test_set_one_multiline_item() { + let json = json!({ "hello": "pretty\nworld" }); + assert_eq!( + print_value(&json), + "{ + hello = '' + pretty + world + ''; +}" + ); } #[test] fn test_filled_set() { - let json = json!({"hello": "world"}); + let json = json!({"hello": "world", "another": "test"}); assert_eq!( - print_value(json), + print_value(&json), "{ + another = \"test\"; hello = \"world\"; }" ); @@ -176,7 +261,7 @@ World ]); assert_eq!( - print_value(json), + print_value(&json), r#"[ "HDMI-0" {