1use alejandra::config::Indentation;23use crate::Value;45pub fn write_identifier(k: &str, out: &mut String) {6 if k.contains(['.', '\'', '\"', '\\', '\n', '\t', '\r', '$']) {7 write_nix_str(k, out);8 } else {9 out.push_str(k);10 }11}1213fn write_nix_obj_key_buf(k: &str, v: &Value, out: &mut String) {14 write_identifier(k, out);15 match v {16 Value::Object(o) if o.len() == 1 => {17 let (k, v) = o.iter().next().unwrap();1819 out.push('.');20 write_nix_obj_key_buf(k, v, out);21 }22 v => {23 out.push_str(" = ");24 write_nix_buf(v, out);25 out.push(';');26 }27 }28}2930pub fn escape_string(str: &str) -> String {31 format!(32 "\"{}\"",33 str.replace('\\', "\\\\")34 .replace('"', "\\\"")35 .replace('\n', "\\n")36 .replace('\t', "\\t")37 .replace('\r', "\\r")38 .replace('$', "\\$")39 )40}4142pub fn write_nix_str(str: &str, out: &mut String) {43 if str.ends_with('\n') {44 out.push_str("''");45 for ele in str.split('\n') {46 out.push('\n');47 out.push_str(48 &ele49 50 .replace("''", "'''")51 52 .replace("${", "''${")53 54 55 56 57 .replace('\t', "''\\t"),58 );59 }60 61 out.push_str("''");62 } else {63 out.push_str(&escape_string(str))64 }65}6667fn write_nix_buf(value: &Value, out: &mut String) {68 match value {69 Value::Null => out.push_str("null"),70 Value::Boolean(v) => out.push_str(if *v { "true" } else { "false" }),71 Value::Number(n) => out.push_str(&format!("{}", n)),72 Value::String(s) => write_nix_str(s, out),73 Value::Array(a) => {74 if a.is_empty() {75 out.push_str("[ ]");76 } else {77 out.push('[');78 for item in a {79 write_nix_buf(item, out);80 out.push('\n');81 }82 out.push(']');83 }84 }85 Value::Object(obj) => {86 if obj.is_empty() {87 out.push_str("{ }")88 } else {89 out.push('{');90 for (k, v) in obj {91 write_nix_obj_key_buf(k, v, out);92 out.push('\n');93 }94 out.push('}');95 }96 }97 };98}99100pub fn write_nix(value: &Value) -> String {101 let mut out = String::new();102 write_nix_buf(value, &mut out);103 let (_, out) = alejandra::format::in_memory(104 "".to_owned(),105 out,106 alejandra::config::Config {107 indentation: Indentation::TwoSpaces,108 },109 );110 out111}