1use crate::Value;2use dprint_core::formatting::{3 condition_resolvers, conditions, format, ConditionResolverContext, Info, PrintItems,4 PrintOptions, Signal,5};67fn write_nix_obj_key_buf(k: &str, v: &Value, out: &mut PrintItems) {8 if k.contains(".") {9 out.push_str("\"");10 out.push_str(k);11 out.push_str("\"");12 } else {13 out.push_str(k);14 }15 match v {16 Value::Object(o) if o.len() == 1 => {17 let (k, v) = o.iter().next().unwrap();1819 out.push_str(".");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_str(";");26 }27 }28}2930fn write_nix_buf(value: &Value, out: &mut PrintItems) {31 match value {32 Value::Null => out.push_str("null"),33 Value::Boolean(v) => out.push_str(if *v { "true" } else { "false" }),34 Value::Number(n) => out.push_str(&format!("{}", n)),35 Value::String(s) => out.push_str(&format!(36 "\"{}\"",37 s.replace('\\', "\\\\")38 .replace('"', "\\\"")39 .replace('\n', "\\n")40 .replace('\t', "\\t")41 .replace('\r', "\\r")42 .replace("$", "''$")43 )),44 Value::Array(a) => {45 if a.is_empty() {46 out.push_str("[ ]");47 } else {48 let start_info = Info::new("start");49 let end_info = Info::new("end");50 let is_multiple_lines = move |ctx: &mut ConditionResolverContext| {51 condition_resolvers::is_multiple_lines(ctx, &start_info, &end_info)52 };53 out.push_str("[");54 out.push_info(start_info);55 out.push_signal(Signal::StartIndent);56 out.push_condition(conditions::if_true_or(57 "array start",58 is_multiple_lines,59 Signal::NewLine.into(),60 Signal::SpaceOrNewLine.into(),61 ));62 for item in a {63 write_nix_buf(item, out);64 out.push_condition(conditions::if_true_or(65 "element separator",66 is_multiple_lines,67 Signal::NewLine.into(),68 Signal::SpaceOrNewLine.into(),69 ));70 }71 out.push_signal(Signal::FinishIndent);72 out.push_info(end_info);73 out.push_str("]");74 }75 }76 Value::Object(obj) => {77 if obj.is_empty() {78 out.push_str("{ }")79 } else {80 let start_info = Info::new("start");81 let end_info = Info::new("end");82 let is_multiple_lines = move |ctx: &mut ConditionResolverContext| {83 condition_resolvers::is_multiple_lines(ctx, &start_info, &end_info)84 };85 out.push_str("{");86 out.push_info(start_info);87 out.push_signal(Signal::StartIndent);88 out.push_condition(conditions::if_true_or(89 "object start",90 is_multiple_lines,91 Signal::NewLine.into(),92 Signal::SpaceOrNewLine.into(),93 ));94 for (k, v) in obj {95 write_nix_obj_key_buf(k, v, out);96 out.push_condition(conditions::if_true_or(97 "element separator",98 is_multiple_lines,99 Signal::NewLine.into(),100 Signal::SpaceOrNewLine.into(),101 ));102 }103 out.push_signal(Signal::FinishIndent);104 out.push_info(end_info);105 out.push_str("}");106 }107 }108 };109}110111pub fn write_nix(value: &Value) -> String {112 format(113 || {114 let mut items = PrintItems::new();115 write_nix_buf(value, &mut items);116 items117 },118 PrintOptions {119 max_width: 120,120 use_tabs: false,121 indent_width: 2,122 new_line_text: "\n",123 },124 )125}