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 out.push_str(k);9 match v {10 Value::Object(o) if o.len() == 1 => {11 let (k, v) = o.iter().next().unwrap();1213 out.push_str(".");14 write_nix_obj_key_buf(k, v, out);15 }16 v => {17 out.push_str(" = ");18 write_nix_buf(v, out);19 out.push_str(";");20 }21 }22}2324fn write_nix_buf(value: &Value, out: &mut PrintItems) {25 match value {26 Value::Null => out.push_str("null"),27 Value::Boolean(v) => out.push_str(if *v { "true" } else { "false" }),28 Value::Number(n) => out.push_str(&format!("{}", n)),29 Value::String(s) => out.push_str(&format!("{:?}", s)),30 Value::Array(a) => {31 if a.is_empty() {32 out.push_str("[ ]");33 } else {34 let start_info = Info::new("start");35 let end_info = Info::new("end");36 let is_multiple_lines = move |ctx: &mut ConditionResolverContext| {37 condition_resolvers::is_multiple_lines(ctx, &start_info, &end_info)38 };39 out.push_str("[");40 out.push_info(start_info);41 out.push_signal(Signal::StartIndent);42 out.push_condition(conditions::if_true_or(43 "array start",44 is_multiple_lines,45 Signal::NewLine.into(),46 Signal::SpaceOrNewLine.into(),47 ));48 for item in a {49 write_nix_buf(item, out);50 out.push_condition(conditions::if_true_or(51 "element separator",52 is_multiple_lines,53 Signal::NewLine.into(),54 Signal::SpaceOrNewLine.into(),55 ));56 }57 out.push_signal(Signal::FinishIndent);58 out.push_info(end_info);59 out.push_str("]");60 }61 }62 Value::Object(obj) => {63 if obj.is_empty() {64 out.push_str("{ }")65 } else {66 let start_info = Info::new("start");67 let end_info = Info::new("end");68 let is_multiple_lines = move |ctx: &mut ConditionResolverContext| {69 condition_resolvers::is_multiple_lines(ctx, &start_info, &end_info)70 };71 out.push_str("{");72 out.push_info(start_info);73 out.push_signal(Signal::StartIndent);74 out.push_condition(conditions::if_true_or(75 "object start",76 is_multiple_lines,77 Signal::NewLine.into(),78 Signal::SpaceOrNewLine.into(),79 ));80 for (k, v) in obj {81 write_nix_obj_key_buf(k, v, out);82 out.push_condition(conditions::if_true_or(83 "element separator",84 is_multiple_lines,85 Signal::NewLine.into(),86 Signal::SpaceOrNewLine.into(),87 ));88 }89 out.push_signal(Signal::FinishIndent);90 out.push_info(end_info);91 out.push_str("}");92 }93 }94 };95}9697pub fn write_nix(value: &Value) -> String {98 format(99 || {100 let mut items = PrintItems::new();101 write_nix_buf(value, &mut items);102 items103 },104 PrintOptions {105 max_width: 120,106 use_tabs: false,107 indent_width: 2,108 new_line_text: "\n",109 },110 )111}